blob: 33749eb274059451fa5bf3c2bddddb0718bd61cd [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{
63
Deepak Kodihalli0b459552018-02-06 06:25:12 -060064// Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
Patrick Venture0b02be92018-08-31 11:55:55 -070065static const std::map<uint8_t, std::string> entityIdToName{
66 {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
67 {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
Deepak Kodihalli0b459552018-02-06 06:25:12 -060068
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030069bool isDCMIPowerMgmtSupported()
70{
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070071 static bool parsed = false;
72 static bool supported = false;
73 if (!parsed)
74 {
75 auto data = parseJSONConfig(gDCMICapabilitiesConfig);
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030076
Vernon Maueryf4eb35d2023-07-27 11:08:49 -070077 supported = (gDCMIPowerMgmtSupported ==
78 data.value(gDCMIPowerMgmtCapability, 0));
79 }
80 return supported;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +030081}
82
Vernon Maueryd4222fd2023-07-27 11:26:51 -070083std::optional<uint32_t> getPcap(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050084{
Vernon Maueryd4222fd2023-07-27 11:26:51 -070085 std::string service{};
86 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
87 pcapPath, service);
88 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -050089 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -070090 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +080091 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -070092 uint32_t pcap{};
93 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
94 powerCapProp, pcap);
95 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +080096 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -070097 log<level::ERR>("Error in getPcap prop",
98 entry("ERROR=%s", ec.message().c_str()));
Tom Josephb9d86f42017-07-26 18:03:47 +053099 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700100 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500101 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700102 return pcap;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500103}
104
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700105std::optional<bool> getPcapEnabled(ipmi::Context::ptr& ctx)
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500106{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700107 std::string service{};
108 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
109 pcapPath, service);
110 if (ec.value())
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500111 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700112 return std::nullopt;
George Liu3e3cc352023-07-26 15:59:31 +0800113 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700114 bool pcapEnabled{};
115 ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
116 powerCapEnableProp, pcapEnabled);
117 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800118 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700119 log<level::ERR>("Error in getPcap prop");
Tom Josephb9d86f42017-07-26 18:03:47 +0530120 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700121 return std::nullopt;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500122 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700123 return pcapEnabled;
Andrew Geissler50c0c8f2017-07-11 16:18:51 -0500124}
Chris Austen1810bec2015-10-13 12:12:39 -0500125
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700126bool setPcap(ipmi::Context::ptr& ctx, const uint32_t powerCap)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530127{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700128 std::string service{};
129 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
130 pcapPath, service);
131 if (ec.value())
Tom Joseph46fa37d2017-07-26 18:11:55 +0530132 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700133 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800134 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700135
136 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
137 powerCapProp, powerCap);
138 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800139 {
140 log<level::ERR>("Error in setPcap property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700141 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530142 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700143 return false;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530144 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700145 return true;
Tom Joseph46fa37d2017-07-26 18:11:55 +0530146}
147
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700148bool setPcapEnable(ipmi::Context::ptr& ctx, bool enabled)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530149{
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700150 std::string service{};
151 boost::system::error_code ec = ipmi::getService(ctx, pcapInterface,
152 pcapPath, service);
153 if (ec.value())
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530154 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700155 return false;
George Liu3e3cc352023-07-26 15:59:31 +0800156 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700157
158 ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
159 powerCapEnableProp, enabled);
160 if (ec.value())
George Liu3e3cc352023-07-26 15:59:31 +0800161 {
162 log<level::ERR>("Error in setPcapEnabled property",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700163 entry("ERROR=%s", ec.message().c_str()));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530164 elog<InternalFailure>();
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700165 return false;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530166 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700167 return true;
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530168}
169
Tom Josephbe5eaa12017-07-12 19:54:44 +0530170void readAssetTagObjectTree(dcmi::assettag::ObjectTree& objectTree)
171{
172 static constexpr auto mapperBusName = "xyz.openbmc_project.ObjectMapper";
173 static constexpr auto mapperObjPath = "/xyz/openbmc_project/object_mapper";
174 static constexpr auto mapperIface = "xyz.openbmc_project.ObjectMapper";
175 static constexpr auto inventoryRoot = "/xyz/openbmc_project/inventory/";
176
Patrick Williams5d82f472022-07-22 19:26:53 -0500177 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530178 auto depth = 0;
179
Patrick Venture0b02be92018-08-31 11:55:55 -0700180 auto mapperCall = bus.new_method_call(mapperBusName, mapperObjPath,
181 mapperIface, "GetSubTree");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530182
183 mapperCall.append(inventoryRoot);
184 mapperCall.append(depth);
185 mapperCall.append(std::vector<std::string>({dcmi::assetTagIntf}));
186
George Liu3e3cc352023-07-26 15:59:31 +0800187 try
Tom Josephbe5eaa12017-07-12 19:54:44 +0530188 {
George Liu3e3cc352023-07-26 15:59:31 +0800189 auto mapperReply = bus.call(mapperCall);
190 mapperReply.read(objectTree);
191
192 if (objectTree.empty())
193 {
194 log<level::ERR>("AssetTag property is not populated");
195 elog<InternalFailure>();
196 }
Tom Josephbe5eaa12017-07-12 19:54:44 +0530197 }
George Liu3e3cc352023-07-26 15:59:31 +0800198 catch (const std::exception& e)
Tom Josephbe5eaa12017-07-12 19:54:44 +0530199 {
George Liu3e3cc352023-07-26 15:59:31 +0800200 log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530201 elog<InternalFailure>();
202 }
203}
204
205std::string readAssetTag()
206{
Patrick Williams5d82f472022-07-22 19:26:53 -0500207 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5eaa12017-07-12 19:54:44 +0530208 dcmi::assettag::ObjectTree objectTree;
209
210 // Read the object tree with the inventory root to figure out the object
211 // that has implemented the Asset tag interface.
212 readAssetTagObjectTree(objectTree);
213
214 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700215 (objectTree.begin()->second.begin()->first).c_str(),
216 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Get");
Tom Josephbe5eaa12017-07-12 19:54:44 +0530217 method.append(dcmi::assetTagIntf);
218 method.append(dcmi::assetTagProp);
219
George Liu3e3cc352023-07-26 15:59:31 +0800220 std::variant<std::string> assetTag;
221 try
Tom Josephbe5eaa12017-07-12 19:54:44 +0530222 {
George Liu3e3cc352023-07-26 15:59:31 +0800223 auto reply = bus.call(method);
224 reply.read(assetTag);
225 return std::get<std::string>(assetTag);
226 }
227 catch (const std::exception& e)
228 {
229 log<level::ERR>("Error in reading asset tag",
230 entry("ERROR=%s", e.what()));
Tom Josephbe5eaa12017-07-12 19:54:44 +0530231 elog<InternalFailure>();
232 }
Tom Josephbe5eaa12017-07-12 19:54:44 +0530233}
234
Tom Josephbe5b9892017-07-15 00:55:23 +0530235void writeAssetTag(const std::string& assetTag)
236{
Patrick Williams5d82f472022-07-22 19:26:53 -0500237 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Tom Josephbe5b9892017-07-15 00:55:23 +0530238 dcmi::assettag::ObjectTree objectTree;
239
240 // Read the object tree with the inventory root to figure out the object
241 // that has implemented the Asset tag interface.
242 readAssetTagObjectTree(objectTree);
243
244 auto method = bus.new_method_call(
Patrick Venture0b02be92018-08-31 11:55:55 -0700245 (objectTree.begin()->second.begin()->first).c_str(),
246 (objectTree.begin()->first).c_str(), dcmi::propIntf, "Set");
Tom Josephbe5b9892017-07-15 00:55:23 +0530247 method.append(dcmi::assetTagIntf);
248 method.append(dcmi::assetTagProp);
Vernon Mauery16b86932019-05-01 08:36:11 -0700249 method.append(std::variant<std::string>(assetTag));
Tom Josephbe5b9892017-07-15 00:55:23 +0530250
George Liu3e3cc352023-07-26 15:59:31 +0800251 try
Tom Josephbe5b9892017-07-15 00:55:23 +0530252 {
George Liu3e3cc352023-07-26 15:59:31 +0800253 auto reply = bus.call(method);
254 }
255 catch (const std::exception& e)
256 {
257 log<level::ERR>("Error in writing asset tag",
258 entry("ERROR=%s", e.what()));
Tom Josephbe5b9892017-07-15 00:55:23 +0530259 elog<InternalFailure>();
260 }
261}
262
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300263std::string getHostName(void)
264{
Patrick Williams5d82f472022-07-22 19:26:53 -0500265 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300266
267 auto service = ipmi::getService(bus, networkConfigIntf, networkConfigObj);
Patrick Venture0b02be92018-08-31 11:55:55 -0700268 auto value = ipmi::getDbusProperty(bus, service, networkConfigObj,
269 networkConfigIntf, hostNameProp);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300270
Vernon Maueryf442e112019-04-09 11:44:36 -0700271 return std::get<std::string>(value);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300272}
273
Thang Tran55cbf552023-01-31 14:43:02 +0700274EthernetInterface::DHCPConf getDHCPEnabled()
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600275{
Patrick Williams5d82f472022-07-22 19:26:53 -0500276 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600277
Johnathan Mantey74a21022018-12-13 13:17:56 -0800278 auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500279 auto ethernetObj = ipmi::getDbusObject(bus, ethernetIntf, networkRoot,
280 ethdevice);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600281 auto service = ipmi::getService(bus, ethernetIntf, ethernetObj.first);
Patrick Venture0b02be92018-08-31 11:55:55 -0700282 auto value = ipmi::getDbusProperty(bus, service, ethernetObj.first,
283 ethernetIntf, "DHCPEnabled");
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600284
Thang Tran55cbf552023-01-31 14:43:02 +0700285 return EthernetInterface::convertDHCPConfFromString(
286 std::get<std::string>(value));
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600287}
288
289bool getDHCPOption(std::string prop)
290{
Patrick Williams5d82f472022-07-22 19:26:53 -0500291 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600292
293 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
294 auto value = ipmi::getDbusProperty(bus, service, dhcpObj, dhcpIntf, prop);
295
Vernon Maueryf442e112019-04-09 11:44:36 -0700296 return std::get<bool>(value);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600297}
298
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600299void setDHCPOption(std::string prop, bool value)
300{
Patrick Williams5d82f472022-07-22 19:26:53 -0500301 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -0600302
303 auto service = ipmi::getService(bus, dhcpIntf, dhcpObj);
304 ipmi::setDbusProperty(bus, service, dhcpObj, dhcpIntf, prop, value);
305}
306
Kirill Pakhomova2573622018-11-02 19:00:18 +0300307Json parseJSONConfig(const std::string& configFile)
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600308{
309 std::ifstream jsonFile(configFile);
310 if (!jsonFile.is_open())
311 {
312 log<level::ERR>("Temperature readings JSON file not found");
313 elog<InternalFailure>();
314 }
315
316 auto data = Json::parse(jsonFile, nullptr, false);
317 if (data.is_discarded())
318 {
319 log<level::ERR>("Temperature readings JSON parser failure");
320 elog<InternalFailure>();
321 }
322
323 return data;
324}
325
Tom Josephbe5eaa12017-07-12 19:54:44 +0530326} // namespace dcmi
Chris Austen1810bec2015-10-13 12:12:39 -0500327
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700328constexpr uint8_t exceptionPowerOff = 0x01;
329ipmi::RspType<uint16_t, // reserved
330 uint8_t, // exception actions
331 uint16_t, // power limit requested in watts
332 uint32_t, // correction time in milliseconds
333 uint16_t, // reserved
334 uint16_t // statistics sampling period in seconds
335 >
336 getPowerLimit(ipmi::Context::ptr ctx, uint16_t reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530337{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300338 if (!dcmi::isDCMIPowerMgmtSupported())
339 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700340 return ipmi::responseInvalidCommand();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300341 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700342 if (reserved)
Tom Josephb9d86f42017-07-26 18:03:47 +0530343 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700344 return ipmi::responseInvalidFieldRequest();
Tom Josephb9d86f42017-07-26 18:03:47 +0530345 }
346
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700347 std::optional<uint16_t> pcapValue = dcmi::getPcap(ctx);
348 std::optional<bool> pcapEnable = dcmi::getPcapEnabled(ctx);
349 if (!pcapValue || !pcapEnable)
350 {
351 return ipmi::responseUnspecifiedError();
352 }
353
354 constexpr uint16_t reserved1{};
355 constexpr uint16_t reserved2{};
Tom Josephb9d86f42017-07-26 18:03:47 +0530356 /*
357 * Exception action if power limit is exceeded and cannot be controlled
358 * with the correction time limit is hardcoded to Hard Power Off system
359 * and log event to SEL.
360 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700361 constexpr uint8_t exception = exceptionPowerOff;
Tom Josephb9d86f42017-07-26 18:03:47 +0530362 /*
363 * Correction time limit and Statistics sampling period is currently not
364 * populated.
365 */
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700366 constexpr uint32_t correctionTime{};
367 constexpr uint16_t statsPeriod{};
368 if (!pcapEnable)
Tom Josephb9d86f42017-07-26 18:03:47 +0530369 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700370 constexpr ipmi::Cc responseNoPowerLimitSet = 0x80;
371 constexpr uint16_t noPcap{};
372 return ipmi::response(responseNoPowerLimitSet, reserved1, exception,
373 noPcap, correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530374 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700375 return ipmi::responseSuccess(reserved1, exception, *pcapValue,
376 correctionTime, reserved2, statsPeriod);
Tom Josephb9d86f42017-07-26 18:03:47 +0530377}
378
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700379ipmi::RspType<> setPowerLimit(ipmi::Context::ptr& ctx, uint16_t reserved1,
380 uint8_t exceptionAction, uint16_t powerLimit,
381 uint32_t correctionTime, uint16_t reserved2,
382 uint16_t statsPeriod)
Tom Joseph46fa37d2017-07-26 18:11:55 +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();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300388 }
389
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700390 // Only process the power limit requested in watts. Return errors
391 // for other fields that are set
392 if (reserved1 || reserved2 || correctionTime || statsPeriod ||
393 exceptionAction != exceptionPowerOff)
Tom Joseph46fa37d2017-07-26 18:11:55 +0530394 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700395 return ipmi::responseInvalidFieldRequest();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530396 }
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700397
398 if (!dcmi::setPcap(ctx, powerLimit))
Tom Joseph46fa37d2017-07-26 18:11:55 +0530399 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700400 return ipmi::responseUnspecifiedError();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530401 }
402
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700403 log<level::INFO>("Set Power Cap", entry("POWERCAP=%u", powerLimit));
Tom Joseph46fa37d2017-07-26 18:11:55 +0530404
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700405 return ipmi::responseSuccess();
Tom Joseph46fa37d2017-07-26 18:11:55 +0530406}
407
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700408ipmi::RspType<> applyPowerLimit(ipmi::Context::ptr& ctx, bool enabled,
409 uint7_t reserved1, uint16_t reserved2)
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530410{
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300411 if (!dcmi::isDCMIPowerMgmtSupported())
412 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300413 log<level::ERR>("DCMI Power management is unsupported!");
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700414 return ipmi::responseInvalidCommand();
415 }
416 if (reserved1 || reserved2)
417 {
418 return ipmi::responseInvalidFieldRequest();
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +0300419 }
420
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700421 if (!dcmi::setPcapEnable(ctx, enabled))
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530422 {
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700423 return ipmi::responseUnspecifiedError();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530424 }
425
426 log<level::INFO>("Set Power Cap Enable",
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700427 entry("POWERCAPENABLE=%u", static_cast<uint8_t>(enabled)));
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530428
Vernon Maueryd4222fd2023-07-27 11:26:51 -0700429 return ipmi::responseSuccess();
Tom Joseph6c8d51b2017-07-26 18:18:06 +0530430}
431
Willy Tu11d68892022-01-20 10:37:34 -0800432ipmi_ret_t getAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
433 ipmi_response_t response, ipmi_data_len_t data_len,
434 ipmi_context_t)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530435{
Patrick Venture0b02be92018-08-31 11:55:55 -0700436 auto requestData =
437 reinterpret_cast<const dcmi::GetAssetTagRequest*>(request);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530438 std::vector<uint8_t> outPayload(sizeof(dcmi::GetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700439 auto responseData =
440 reinterpret_cast<dcmi::GetAssetTagResponse*>(outPayload.data());
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530441
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530442 // Verify offset to read and number of bytes to read are not exceeding the
443 // range.
444 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
445 (requestData->bytes > dcmi::maxBytes) ||
446 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
447 {
448 *data_len = 0;
449 return IPMI_CC_PARM_OUT_OF_RANGE;
450 }
451
452 std::string assetTag;
453
454 try
455 {
456 assetTag = dcmi::readAssetTag();
457 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500458 catch (const InternalFailure& e)
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530459 {
460 *data_len = 0;
461 return IPMI_CC_UNSPECIFIED_ERROR;
462 }
463
Tom Joseph6f6dd4d2017-07-12 20:07:11 +0530464 // Return if the asset tag is not populated.
465 if (!assetTag.size())
466 {
467 responseData->tagLength = 0;
468 memcpy(response, outPayload.data(), outPayload.size());
469 *data_len = outPayload.size();
470 return IPMI_CC_OK;
471 }
472
473 // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to suit
474 // Get Asset Tag command.
475 if (assetTag.size() > dcmi::assetTagMaxSize)
476 {
477 assetTag.resize(dcmi::assetTagMaxSize);
478 }
479
480 // If the requested offset is beyond the asset tag size.
481 if (requestData->offset >= assetTag.size())
482 {
483 *data_len = 0;
484 return IPMI_CC_PARM_OUT_OF_RANGE;
485 }
486
487 auto returnData = assetTag.substr(requestData->offset, requestData->bytes);
488
489 responseData->tagLength = assetTag.size();
490
491 memcpy(response, outPayload.data(), outPayload.size());
492 memcpy(static_cast<uint8_t*>(response) + outPayload.size(),
493 returnData.data(), returnData.size());
494 *data_len = outPayload.size() + returnData.size();
495
496 return IPMI_CC_OK;
497}
498
Willy Tu11d68892022-01-20 10:37:34 -0800499ipmi_ret_t setAssetTag(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
500 ipmi_response_t response, ipmi_data_len_t data_len,
501 ipmi_context_t)
Tom Joseph545dd232017-07-12 20:20:49 +0530502{
Patrick Venture0b02be92018-08-31 11:55:55 -0700503 auto requestData =
504 reinterpret_cast<const dcmi::SetAssetTagRequest*>(request);
Tom Joseph545dd232017-07-12 20:20:49 +0530505 std::vector<uint8_t> outPayload(sizeof(dcmi::SetAssetTagResponse));
Patrick Venture0b02be92018-08-31 11:55:55 -0700506 auto responseData =
507 reinterpret_cast<dcmi::SetAssetTagResponse*>(outPayload.data());
Tom Joseph545dd232017-07-12 20:20:49 +0530508
Tom Joseph545dd232017-07-12 20:20:49 +0530509 // Verify offset to read and number of bytes to read are not exceeding the
510 // range.
511 if ((requestData->offset > dcmi::assetTagMaxOffset) ||
512 (requestData->bytes > dcmi::maxBytes) ||
513 ((requestData->offset + requestData->bytes) > dcmi::assetTagMaxSize))
514 {
515 *data_len = 0;
516 return IPMI_CC_PARM_OUT_OF_RANGE;
517 }
518
519 std::string assetTag;
520
521 try
522 {
523 assetTag = dcmi::readAssetTag();
524
525 if (requestData->offset > assetTag.size())
526 {
527 *data_len = 0;
528 return IPMI_CC_PARM_OUT_OF_RANGE;
529 }
530
531 assetTag.replace(requestData->offset,
532 assetTag.size() - requestData->offset,
533 static_cast<const char*>(request) +
Patrick Venture0b02be92018-08-31 11:55:55 -0700534 sizeof(dcmi::SetAssetTagRequest),
Tom Joseph545dd232017-07-12 20:20:49 +0530535 requestData->bytes);
536
537 dcmi::writeAssetTag(assetTag);
538
Tom Joseph545dd232017-07-12 20:20:49 +0530539 responseData->tagLength = assetTag.size();
540 memcpy(response, outPayload.data(), outPayload.size());
541 *data_len = outPayload.size();
542
543 return IPMI_CC_OK;
544 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500545 catch (const InternalFailure& e)
Tom Joseph545dd232017-07-12 20:20:49 +0530546 {
547 *data_len = 0;
548 return IPMI_CC_UNSPECIFIED_ERROR;
549 }
550}
551
Willy Tu11d68892022-01-20 10:37:34 -0800552ipmi_ret_t getMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
553 ipmi_response_t response, ipmi_data_len_t data_len,
554 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300555{
Patrick Venture0b02be92018-08-31 11:55:55 -0700556 auto requestData =
557 reinterpret_cast<const dcmi::GetMgmntCtrlIdStrRequest*>(request);
558 auto responseData =
559 reinterpret_cast<dcmi::GetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300560 std::string hostName;
561
562 *data_len = 0;
563
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700564 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300565 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen)
566 {
567 return IPMI_CC_INVALID_FIELD_REQUEST;
568 }
569
570 try
571 {
572 hostName = dcmi::getHostName();
573 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500574 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300575 {
576 return IPMI_CC_UNSPECIFIED_ERROR;
577 }
578
579 if (requestData->offset > hostName.length())
580 {
581 return IPMI_CC_PARM_OUT_OF_RANGE;
582 }
583 auto responseStr = hostName.substr(requestData->offset, requestData->bytes);
584 auto responseStrLen = std::min(static_cast<std::size_t>(requestData->bytes),
Patrick Venture0b02be92018-08-31 11:55:55 -0700585 responseStr.length() + 1);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300586 responseData->strLen = hostName.length();
587 std::copy(begin(responseStr), end(responseStr), responseData->data);
588
589 *data_len = sizeof(*responseData) + responseStrLen;
590 return IPMI_CC_OK;
591}
592
Willy Tu11d68892022-01-20 10:37:34 -0800593ipmi_ret_t setMgmntCtrlIdStr(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
594 ipmi_response_t response, ipmi_data_len_t data_len,
595 ipmi_context_t)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300596{
597 static std::array<char, dcmi::maxCtrlIdStrLen + 1> newCtrlIdStr;
598
Patrick Venture0b02be92018-08-31 11:55:55 -0700599 auto requestData =
600 reinterpret_cast<const dcmi::SetMgmntCtrlIdStrRequest*>(request);
601 auto responseData =
602 reinterpret_cast<dcmi::SetMgmntCtrlIdStrResponse*>(response);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300603
604 *data_len = 0;
605
William A. Kennington III5d06cc62019-04-25 02:10:55 -0700606 if (requestData->bytes > dcmi::maxBytes ||
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300607 requestData->offset + requestData->bytes > dcmi::maxCtrlIdStrLen + 1 ||
Patrick Venture0b02be92018-08-31 11:55:55 -0700608 (requestData->offset + requestData->bytes ==
609 dcmi::maxCtrlIdStrLen + 1 &&
610 requestData->data[requestData->bytes - 1] != '\0'))
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300611 {
612 return IPMI_CC_INVALID_FIELD_REQUEST;
613 }
614
615 try
616 {
617 /* if there is no old value and offset is not 0 */
618 if (newCtrlIdStr[0] == '\0' && requestData->offset != 0)
619 {
620 /* read old ctrlIdStr */
621 auto hostName = dcmi::getHostName();
622 hostName.resize(dcmi::maxCtrlIdStrLen);
623 std::copy(begin(hostName), end(hostName), begin(newCtrlIdStr));
624 newCtrlIdStr[hostName.length()] = '\0';
625 }
626
627 /* replace part of string and mark byte after the last as \0 */
Patrick Venture0b02be92018-08-31 11:55:55 -0700628 auto restStrIter =
629 std::copy_n(requestData->data, requestData->bytes,
630 begin(newCtrlIdStr) + requestData->offset);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300631 /* if the last written byte is not 64th - add '\0' */
632 if (requestData->offset + requestData->bytes <= dcmi::maxCtrlIdStrLen)
633 {
634 *restStrIter = '\0';
635 }
636
637 /* if input data contains '\0' whole string is sent - update hostname */
638 auto it = std::find(requestData->data,
Patrick Venture0b02be92018-08-31 11:55:55 -0700639 requestData->data + requestData->bytes, '\0');
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300640 if (it != requestData->data + requestData->bytes)
641 {
Patrick Williams5d82f472022-07-22 19:26:53 -0500642 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300643 ipmi::setDbusProperty(bus, dcmi::networkServiceName,
Patrick Venture0b02be92018-08-31 11:55:55 -0700644 dcmi::networkConfigObj,
645 dcmi::networkConfigIntf, dcmi::hostNameProp,
646 std::string(newCtrlIdStr.data()));
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300647 }
648 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500649 catch (const InternalFailure& e)
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300650 {
651 *data_len = 0;
652 return IPMI_CC_UNSPECIFIED_ERROR;
653 }
654
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +0300655 responseData->offset = requestData->offset + requestData->bytes;
656 *data_len = sizeof(*responseData);
657 return IPMI_CC_OK;
658}
659
Patrick Venture0b02be92018-08-31 11:55:55 -0700660// List of the capabilities under each parameter
661dcmi::DCMICaps dcmiCaps = {
662 // Supported DCMI Capabilities
663 {dcmi::DCMICapParameters::SUPPORTED_DCMI_CAPS,
664 {3,
665 {{"PowerManagement", 2, 0, 1},
666 {"OOBSecondaryLan", 3, 2, 1},
667 {"SerialTMODE", 3, 1, 1},
668 {"InBandSystemInterfaceChannel", 3, 0, 1}}}},
669 // Mandatory Platform Attributes
670 {dcmi::DCMICapParameters::MANDATORY_PLAT_ATTRIBUTES,
671 {5,
672 {{"SELAutoRollOver", 1, 15, 1},
673 {"FlushEntireSELUponRollOver", 1, 14, 1},
674 {"RecordLevelSELFlushUponRollOver", 1, 13, 1},
675 {"NumberOfSELEntries", 1, 0, 12},
676 {"TempMonitoringSamplingFreq", 5, 0, 8}}}},
677 // Optional Platform Attributes
678 {dcmi::DCMICapParameters::OPTIONAL_PLAT_ATTRIBUTES,
679 {2,
680 {{"PowerMgmtDeviceSlaveAddress", 1, 1, 7},
681 {"BMCChannelNumber", 2, 4, 4},
682 {"DeviceRivision", 2, 0, 4}}}},
683 // Manageability Access Attributes
684 {dcmi::DCMICapParameters::MANAGEABILITY_ACCESS_ATTRIBUTES,
685 {3,
686 {{"MandatoryPrimaryLanOOBSupport", 1, 0, 8},
687 {"OptionalSecondaryLanOOBSupport", 2, 0, 8},
688 {"OptionalSerialOOBMTMODECapability", 3, 0, 8}}}}};
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600689
Willy Tu11d68892022-01-20 10:37:34 -0800690ipmi_ret_t getDCMICapabilities(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
691 ipmi_response_t response,
692 ipmi_data_len_t data_len, ipmi_context_t)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600693{
Kirill Pakhomova2573622018-11-02 19:00:18 +0300694 std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600695 if (!dcmiCapFile.is_open())
696 {
697 log<level::ERR>("DCMI Capabilities file not found");
698 return IPMI_CC_UNSPECIFIED_ERROR;
699 }
700
701 auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
702 if (data.is_discarded())
703 {
704 log<level::ERR>("DCMI Capabilities JSON parser failure");
705 return IPMI_CC_UNSPECIFIED_ERROR;
706 }
707
Patrick Venture0b02be92018-08-31 11:55:55 -0700708 auto requestData =
709 reinterpret_cast<const dcmi::GetDCMICapRequest*>(request);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600710
Patrick Venture0b02be92018-08-31 11:55:55 -0700711 // get list of capabilities in a parameter
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600712 auto caps =
713 dcmiCaps.find(static_cast<dcmi::DCMICapParameters>(requestData->param));
714 if (caps == dcmiCaps.end())
715 {
716 log<level::ERR>("Invalid input parameter");
717 return IPMI_CC_INVALID_FIELD_REQUEST;
718 }
719
Patrick Venture0b02be92018-08-31 11:55:55 -0700720 auto responseData = reinterpret_cast<dcmi::GetDCMICapResponse*>(response);
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600721
Patrick Venture0b02be92018-08-31 11:55:55 -0700722 // For each capabilities in a parameter fill the data from
723 // the json file based on the capability name.
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600724 for (auto cap : caps->second.capList)
725 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700726 // If the data is beyond first byte boundary, insert in a
727 // 16bit pattern for example number of SEL entries are represented
728 // in 12bits.
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300729 if ((cap.length + cap.position) > dcmi::gByteBitSize)
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600730 {
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300731 uint16_t val = data.value(cap.name.c_str(), 0);
732 // According to DCMI spec v1.5, max number of SEL entries is
733 // 4096, but bit 12b of DCMI capabilities Mandatory Platform
734 // Attributes field is reserved and therefore we can use only
735 // the provided 12 bits with maximum value of 4095.
736 // We're playing safe here by applying the mask
737 // to ensure that provided value will fit into 12 bits.
738 if (cap.length > dcmi::gByteBitSize)
739 {
740 val &= dcmi::gMaxSELEntriesMask;
741 }
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600742 val <<= cap.position;
Kirill Pakhomovdb5d9b02018-11-06 19:17:51 +0300743 responseData->data[cap.bytePosition - 1] |=
744 static_cast<uint8_t>(val);
745 responseData->data[cap.bytePosition] |= val >> dcmi::gByteBitSize;
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600746 }
747 else
748 {
749 responseData->data[cap.bytePosition - 1] |=
750 data.value(cap.name.c_str(), 0) << cap.position;
751 }
752 }
753
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -0600754 responseData->major = DCMI_SPEC_MAJOR_VERSION;
755 responseData->minor = DCMI_SPEC_MINOR_VERSION;
756 responseData->paramRevision = DCMI_PARAMETER_REVISION;
757 *data_len = sizeof(*responseData) + caps->second.size;
758
759 return IPMI_CC_OK;
760}
761
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600762namespace dcmi
763{
764namespace temp_readings
765{
766
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600767Temperature readTemp(const std::string& dbusService,
768 const std::string& dbusPath)
769{
770 // Read the temperature value from d-bus object. Need some conversion.
771 // As per the interface xyz.openbmc_project.Sensor.Value, the temperature
James Feist9cc0ea52018-10-09 10:53:11 -0700772 // is an double and in degrees C. It needs to be scaled by using the
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600773 // formula Value * 10^Scale. The ipmi spec has the temperature as a uint8_t,
774 // with a separate single bit for the sign.
775
Patrick Williams5d82f472022-07-22 19:26:53 -0500776 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Patrick Venture0b02be92018-08-31 11:55:55 -0700777 auto result = ipmi::getAllDbusProperties(
778 bus, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value");
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500779 auto temperature = std::visit(ipmi::VariantToDoubleVisitor(),
780 result.at("Value"));
James Feist9cc0ea52018-10-09 10:53:11 -0700781 double absTemp = std::abs(temperature);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600782
James Feist9cc0ea52018-10-09 10:53:11 -0700783 auto findFactor = result.find("Scale");
784 double factor = 0.0;
785 if (findFactor != result.end())
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600786 {
Vernon Maueryf442e112019-04-09 11:44:36 -0700787 factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600788 }
James Feist9cc0ea52018-10-09 10:53:11 -0700789 double scale = std::pow(10, factor);
790
791 auto tempDegrees = absTemp * scale;
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600792 // Max absolute temp as per ipmi spec is 128.
793 if (tempDegrees > maxTemp)
794 {
795 tempDegrees = maxTemp;
796 }
797
798 return std::make_tuple(static_cast<uint8_t>(tempDegrees),
799 (temperature < 0));
800}
801
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600802std::tuple<Response, NumInstances> read(const std::string& type,
803 uint8_t instance)
804{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600805 Response response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500806 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600807
808 if (!instance)
809 {
810 log<level::ERR>("Expected non-zero instance");
811 elog<InternalFailure>();
812 }
813
Kirill Pakhomova2573622018-11-02 19:00:18 +0300814 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600815 static const std::vector<Json> empty{};
816 std::vector<Json> readings = data.value(type, empty);
817 size_t numInstances = readings.size();
818 for (const auto& j : readings)
819 {
820 uint8_t instanceNum = j.value("instance", 0);
821 // Not the instance we're interested in
822 if (instanceNum != instance)
823 {
824 continue;
825 }
826
827 std::string path = j.value("dbus", "");
828 std::string service;
829 try
830 {
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -0500831 service = ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value",
832 path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600833 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500834 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600835 {
836 log<level::DEBUG>(e.what());
837 return std::make_tuple(response, numInstances);
838 }
839
840 response.instance = instance;
841 uint8_t temp{};
842 bool sign{};
843 std::tie(temp, sign) = readTemp(service, path);
844 response.temperature = temp;
845 response.sign = sign;
846
847 // Found the instance we're interested in
848 break;
849 }
850
851 if (numInstances > maxInstances)
852 {
853 numInstances = maxInstances;
854 }
855 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600856}
857
858std::tuple<ResponseList, NumInstances> readAll(const std::string& type,
859 uint8_t instanceStart)
860{
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600861 ResponseList response{};
Patrick Williams5d82f472022-07-22 19:26:53 -0500862 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600863
864 size_t numInstances = 0;
Kirill Pakhomova2573622018-11-02 19:00:18 +0300865 auto data = parseJSONConfig(gDCMISensorsConfig);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600866 static const std::vector<Json> empty{};
867 std::vector<Json> readings = data.value(type, empty);
868 numInstances = readings.size();
869 for (const auto& j : readings)
870 {
871 try
872 {
873 // Max of 8 response data sets
874 if (response.size() == maxDataSets)
875 {
876 break;
877 }
878
879 uint8_t instanceNum = j.value("instance", 0);
880 // Not in the instance range we're interested in
881 if (instanceNum < instanceStart)
882 {
883 continue;
884 }
885
886 std::string path = j.value("dbus", "");
887 auto service =
Patrick Venture0b02be92018-08-31 11:55:55 -0700888 ipmi::getService(bus, "xyz.openbmc_project.Sensor.Value", path);
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600889
890 Response r{};
891 r.instance = instanceNum;
892 uint8_t temp{};
893 bool sign{};
894 std::tie(temp, sign) = readTemp(service, path);
895 r.temperature = temp;
896 r.sign = sign;
897 response.push_back(r);
898 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500899 catch (const std::exception& e)
Deepak Kodihallib1e8fba2018-01-24 04:57:10 -0600900 {
901 log<level::DEBUG>(e.what());
902 continue;
903 }
904 }
905
906 if (numInstances > maxInstances)
907 {
908 numInstances = maxInstances;
909 }
910 return std::make_tuple(response, numInstances);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600911}
912
Patrick Venture0b02be92018-08-31 11:55:55 -0700913} // namespace temp_readings
914} // namespace dcmi
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600915
Willy Tu11d68892022-01-20 10:37:34 -0800916ipmi_ret_t getTempReadings(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
917 ipmi_response_t response, ipmi_data_len_t data_len,
918 ipmi_context_t)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600919{
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600920 auto requestData =
921 reinterpret_cast<const dcmi::GetTempReadingsRequest*>(request);
922 auto responseData =
923 reinterpret_cast<dcmi::GetTempReadingsResponseHdr*>(response);
924
925 if (*data_len != sizeof(dcmi::GetTempReadingsRequest))
926 {
927 log<level::ERR>("Malformed request data",
928 entry("DATA_SIZE=%d", *data_len));
929 return IPMI_CC_REQ_DATA_LEN_INVALID;
930 }
931 *data_len = 0;
932
Deepak Kodihalli0b459552018-02-06 06:25:12 -0600933 auto it = dcmi::entityIdToName.find(requestData->entityId);
934 if (it == dcmi::entityIdToName.end())
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600935 {
936 log<level::ERR>("Unknown Entity ID",
937 entry("ENTITY_ID=%d", requestData->entityId));
938 return IPMI_CC_INVALID_FIELD_REQUEST;
939 }
940
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600941 if (requestData->sensorType != dcmi::temperatureSensorType)
942 {
943 log<level::ERR>("Invalid sensor type",
944 entry("SENSOR_TYPE=%d", requestData->sensorType));
945 return IPMI_CC_INVALID_FIELD_REQUEST;
946 }
947
948 dcmi::temp_readings::ResponseList temps{};
949 try
950 {
951 if (!requestData->entityInstance)
952 {
953 // Read all instances
954 std::tie(temps, responseData->numInstances) =
955 dcmi::temp_readings::readAll(it->second,
956 requestData->instanceStart);
957 }
958 else
959 {
960 // Read one instance
961 temps.resize(1);
962 std::tie(temps[0], responseData->numInstances) =
963 dcmi::temp_readings::read(it->second,
964 requestData->entityInstance);
965 }
966 responseData->numDataSets = temps.size();
967 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -0500968 catch (const InternalFailure& e)
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600969 {
970 return IPMI_CC_UNSPECIFIED_ERROR;
971 }
972
Patrick Venture0b02be92018-08-31 11:55:55 -0700973 size_t payloadSize = temps.size() * sizeof(dcmi::temp_readings::Response);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600974 if (!temps.empty())
975 {
976 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -0700977 temps.data(), payloadSize);
Deepak Kodihalliee717d72018-01-24 04:53:09 -0600978 }
979 *data_len = sizeof(dcmi::GetTempReadingsResponseHdr) + payloadSize;
980
981 return IPMI_CC_OK;
982}
983
Patrick Williams5d82f472022-07-22 19:26:53 -0500984int64_t getPowerReading(sdbusplus::bus_t& bus)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600985{
986 std::ifstream sensorFile(POWER_READING_SENSOR);
987 std::string objectPath;
988 if (!sensorFile.is_open())
989 {
990 log<level::ERR>("Power reading configuration file not found",
Patrick Venture0b02be92018-08-31 11:55:55 -0700991 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -0600992 elog<InternalFailure>();
993 }
994
995 auto data = nlohmann::json::parse(sensorFile, nullptr, false);
996 if (data.is_discarded())
997 {
998 log<level::ERR>("Error in parsing configuration file",
Patrick Venture0b02be92018-08-31 11:55:55 -0700999 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001000 elog<InternalFailure>();
1001 }
1002
1003 objectPath = data.value("path", "");
1004 if (objectPath.empty())
1005 {
1006 log<level::ERR>("Power sensor D-Bus object path is empty",
1007 entry("POWER_SENSOR_FILE=%s", POWER_READING_SENSOR));
1008 elog<InternalFailure>();
1009 }
1010
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001011 // Return default value if failed to read from D-Bus object
1012 int64_t power = 0;
1013 try
1014 {
1015 auto service = ipmi::getService(bus, SENSOR_VALUE_INTF, objectPath);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001016
Patrick Venture0b02be92018-08-31 11:55:55 -07001017 // Read the sensor value and scale properties
Chris Cain4cc61e02022-01-12 17:23:14 -06001018 auto value = ipmi::getDbusProperty(
1019 bus, service, objectPath, SENSOR_VALUE_INTF, SENSOR_VALUE_PROP);
1020 power = std::get<double>(value);
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001021 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001022 catch (const std::exception& e)
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001023 {
Chris Cain4cc61e02022-01-12 17:23:14 -06001024 log<level::ERR>("Failure to read power value from D-Bus object",
1025 entry("OBJECT_PATH=%s", objectPath.c_str()),
1026 entry("INTERFACE=%s", SENSOR_VALUE_INTF));
Marri Devender Raoce6a7952018-02-11 08:45:00 -06001027 }
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001028 return power;
1029}
1030
Willy Tu11d68892022-01-20 10:37:34 -08001031ipmi_ret_t setDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1032 ipmi_response_t, ipmi_data_len_t data_len,
1033 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001034{
Patrick Venture0b02be92018-08-31 11:55:55 -07001035 auto requestData =
1036 reinterpret_cast<const dcmi::SetConfParamsRequest*>(request);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001037
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001038 if (*data_len < DCMI_SET_CONF_PARAM_REQ_PACKET_MIN_SIZE ||
Patrick Venture0b02be92018-08-31 11:55:55 -07001039 *data_len > DCMI_SET_CONF_PARAM_REQ_PACKET_MAX_SIZE)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001040 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001041 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001042 entry("PACKET SIZE=%d", *data_len));
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001043 *data_len = 0;
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001044 return IPMI_CC_INVALID_FIELD_REQUEST;
1045 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001046 *data_len = 0;
1047
1048 try
1049 {
1050 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001051 switch (
1052 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001053 {
1054 case dcmi::DCMIConfigParameters::ActivateDHCP:
1055
1056 if ((requestData->data[0] & DCMI_ACTIVATE_DHCP_MASK) &&
Thang Tran55cbf552023-01-31 14:43:02 +07001057 (dcmi::getDHCPEnabled() !=
1058 EthernetInterface::DHCPConf::none))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001059 {
Patrick Venture0b02be92018-08-31 11:55:55 -07001060 // When these conditions are met we have to trigger DHCP
1061 // protocol restart using the latest parameter settings, but
1062 // as per n/w manager design, each time when we update n/w
1063 // parameters, n/w service is restarted. So we no need to
1064 // take any action in this case.
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001065 }
1066 break;
1067
1068 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1069
1070 if (requestData->data[0] & DCMI_OPTION_12_MASK)
1071 {
1072 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, true);
1073 }
1074 else
1075 {
1076 dcmi::setDHCPOption(DHCP_OPT12_ENABLED, false);
1077 }
1078
1079 // Systemd-networkd doesn't support Random Back off
1080 if (requestData->data[0] & DCMI_RAND_BACK_OFF_MASK)
1081 {
1082 return IPMI_CC_INVALID;
1083 }
1084 break;
1085 // Systemd-networkd doesn't allow to configure DHCP timigs
1086 case dcmi::DCMIConfigParameters::DHCPTiming1:
1087 case dcmi::DCMIConfigParameters::DHCPTiming2:
1088 case dcmi::DCMIConfigParameters::DHCPTiming3:
1089 default:
1090 return IPMI_CC_INVALID;
1091 }
1092 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001093 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001094 {
1095 log<level::ERR>(e.what());
1096 return IPMI_CC_UNSPECIFIED_ERROR;
1097 }
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001098 return IPMI_CC_OK;
1099}
1100
Willy Tu11d68892022-01-20 10:37:34 -08001101ipmi_ret_t getDCMIConfParams(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1102 ipmi_response_t response, ipmi_data_len_t data_len,
1103 ipmi_context_t)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001104{
Patrick Venture0b02be92018-08-31 11:55:55 -07001105 auto requestData =
1106 reinterpret_cast<const dcmi::GetConfParamsRequest*>(request);
1107 auto responseData =
1108 reinterpret_cast<dcmi::GetConfParamsResponse*>(response);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001109
1110 responseData->data[0] = 0x00;
1111
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001112 if (*data_len != sizeof(dcmi::GetConfParamsRequest))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001113 {
William A. Kennington III5d06cc62019-04-25 02:10:55 -07001114 log<level::ERR>("Invalid Requested Packet size",
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001115 entry("PACKET SIZE=%d", *data_len));
1116 return IPMI_CC_INVALID_FIELD_REQUEST;
1117 }
1118
1119 *data_len = 0;
1120
1121 try
1122 {
1123 // Take action based on the Parameter Selector
Patrick Venture0b02be92018-08-31 11:55:55 -07001124 switch (
1125 static_cast<dcmi::DCMIConfigParameters>(requestData->paramSelect))
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001126 {
1127 case dcmi::DCMIConfigParameters::ActivateDHCP:
1128 responseData->data[0] = DCMI_ACTIVATE_DHCP_REPLY;
1129 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1130 break;
1131 case dcmi::DCMIConfigParameters::DiscoveryConfig:
1132 if (dcmi::getDHCPOption(DHCP_OPT12_ENABLED))
1133 {
1134 responseData->data[0] |= DCMI_OPTION_12_MASK;
1135 }
1136 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1137 break;
1138 // Get below values from Systemd-networkd source code
1139 case dcmi::DCMIConfigParameters::DHCPTiming1:
1140 responseData->data[0] = DHCP_TIMING1;
1141 *data_len = sizeof(dcmi::GetConfParamsResponse) + 1;
1142 break;
1143 case dcmi::DCMIConfigParameters::DHCPTiming2:
1144 responseData->data[0] = DHCP_TIMING2_LOWER;
1145 responseData->data[1] = DHCP_TIMING2_UPPER;
1146 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1147 break;
1148 case dcmi::DCMIConfigParameters::DHCPTiming3:
1149 responseData->data[0] = DHCP_TIMING3_LOWER;
1150 responseData->data[1] = DHCP_TIMING3_UPPER;
1151 *data_len = sizeof(dcmi::GetConfParamsResponse) + 2;
1152 break;
1153 default:
1154 *data_len = 0;
1155 return IPMI_CC_INVALID;
1156 }
1157 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001158 catch (const std::exception& e)
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001159 {
1160 log<level::ERR>(e.what());
1161 return IPMI_CC_UNSPECIFIED_ERROR;
1162 }
1163
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001164 responseData->major = DCMI_SPEC_MAJOR_VERSION;
1165 responseData->minor = DCMI_SPEC_MINOR_VERSION;
1166 responseData->paramRevision = DCMI_CONFIG_PARAMETER_REVISION;
1167
1168 return IPMI_CC_OK;
1169}
1170
Willy Tu11d68892022-01-20 10:37:34 -08001171ipmi_ret_t getPowerReading(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
1172 ipmi_response_t response, ipmi_data_len_t data_len,
1173 ipmi_context_t)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001174{
Chalapathi Venkataramashetty90e81fa2021-05-11 09:13:23 +00001175 *data_len = 0;
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001176 if (!dcmi::isDCMIPowerMgmtSupported())
1177 {
Kirill Pakhomov2c2af2c2018-11-06 16:06:10 +03001178 log<level::ERR>("DCMI Power management is unsupported!");
1179 return IPMI_CC_INVALID;
1180 }
1181
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001182 ipmi_ret_t rc = IPMI_CC_OK;
Patrick Venture0b02be92018-08-31 11:55:55 -07001183 auto responseData =
1184 reinterpret_cast<dcmi::GetPowerReadingResponse*>(response);
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001185
Patrick Williams5d82f472022-07-22 19:26:53 -05001186 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001187 int64_t power = 0;
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001188 try
1189 {
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001190 power = getPowerReading(bus);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001191 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001192 catch (const InternalFailure& e)
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001193 {
1194 log<level::ERR>("Error in reading power sensor value",
1195 entry("INTERFACE=%s", SENSOR_VALUE_INTF),
1196 entry("PROPERTY=%s", SENSOR_VALUE_PROP));
1197 return IPMI_CC_UNSPECIFIED_ERROR;
1198 }
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001199
1200 // TODO: openbmc/openbmc#2819
Gunnar Mills8466b792018-03-23 12:18:12 -05001201 // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
Marri Devender Rao9c966e02018-01-22 05:55:10 -06001202 // PowerReadingState readings need to be populated
1203 // after Telemetry changes.
1204 uint16_t totalPower = static_cast<uint16_t>(power);
1205 responseData->currentPower = totalPower;
1206 responseData->minimumPower = totalPower;
1207 responseData->maximumPower = totalPower;
1208 responseData->averagePower = totalPower;
1209
1210 *data_len = sizeof(*responseData);
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001211 return rc;
1212}
1213
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001214namespace dcmi
1215{
1216namespace sensor_info
1217{
1218
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001219Response createFromJson(const Json& config)
1220{
1221 Response response{};
1222 uint16_t recordId = config.value("record_id", 0);
1223 response.recordIdLsb = recordId & 0xFF;
1224 response.recordIdMsb = (recordId >> 8) & 0xFF;
1225 return response;
1226}
1227
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001228std::tuple<Response, NumInstances> read(const std::string& type,
Patrick Venture0b02be92018-08-31 11:55:55 -07001229 uint8_t instance, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001230{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001231 Response response{};
1232
1233 if (!instance)
1234 {
1235 log<level::ERR>("Expected non-zero instance");
1236 elog<InternalFailure>();
1237 }
1238
1239 static const std::vector<Json> empty{};
1240 std::vector<Json> readings = config.value(type, empty);
1241 size_t numInstances = readings.size();
1242 for (const auto& reading : readings)
1243 {
1244 uint8_t instanceNum = reading.value("instance", 0);
1245 // Not the instance we're interested in
1246 if (instanceNum != instance)
1247 {
1248 continue;
1249 }
1250
1251 response = createFromJson(reading);
1252
1253 // Found the instance we're interested in
1254 break;
1255 }
1256
1257 if (numInstances > maxInstances)
1258 {
1259 log<level::DEBUG>("Trimming IPMI num instances",
1260 entry("NUM_INSTANCES=%d", numInstances));
1261 numInstances = maxInstances;
1262 }
1263 return std::make_tuple(response, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001264}
1265
Patrick Venture0b02be92018-08-31 11:55:55 -07001266std::tuple<ResponseList, NumInstances>
1267 readAll(const std::string& type, uint8_t instanceStart, const Json& config)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001268{
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001269 ResponseList responses{};
1270
1271 size_t numInstances = 0;
1272 static const std::vector<Json> empty{};
1273 std::vector<Json> readings = config.value(type, empty);
1274 numInstances = readings.size();
1275 for (const auto& reading : readings)
1276 {
1277 try
1278 {
1279 // Max of 8 records
1280 if (responses.size() == maxRecords)
1281 {
1282 break;
1283 }
1284
1285 uint8_t instanceNum = reading.value("instance", 0);
1286 // Not in the instance range we're interested in
1287 if (instanceNum < instanceStart)
1288 {
1289 continue;
1290 }
1291
1292 Response response = createFromJson(reading);
1293 responses.push_back(response);
1294 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001295 catch (const std::exception& e)
Deepak Kodihallidd4cff12018-02-06 06:48:29 -06001296 {
1297 log<level::DEBUG>(e.what());
1298 continue;
1299 }
1300 }
1301
1302 if (numInstances > maxInstances)
1303 {
1304 log<level::DEBUG>("Trimming IPMI num instances",
1305 entry("NUM_INSTANCES=%d", numInstances));
1306 numInstances = maxInstances;
1307 }
1308 return std::make_tuple(responses, numInstances);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001309}
1310
1311} // namespace sensor_info
1312} // namespace dcmi
1313
Willy Tu11d68892022-01-20 10:37:34 -08001314ipmi_ret_t getSensorInfo(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
1315 ipmi_response_t response, ipmi_data_len_t data_len,
1316 ipmi_context_t)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001317{
1318 auto requestData =
1319 reinterpret_cast<const dcmi::GetSensorInfoRequest*>(request);
1320 auto responseData =
1321 reinterpret_cast<dcmi::GetSensorInfoResponseHdr*>(response);
1322
1323 if (*data_len != sizeof(dcmi::GetSensorInfoRequest))
1324 {
1325 log<level::ERR>("Malformed request data",
1326 entry("DATA_SIZE=%d", *data_len));
1327 return IPMI_CC_REQ_DATA_LEN_INVALID;
1328 }
1329 *data_len = 0;
1330
1331 auto it = dcmi::entityIdToName.find(requestData->entityId);
1332 if (it == dcmi::entityIdToName.end())
1333 {
1334 log<level::ERR>("Unknown Entity ID",
1335 entry("ENTITY_ID=%d", requestData->entityId));
1336 return IPMI_CC_INVALID_FIELD_REQUEST;
1337 }
1338
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001339 if (requestData->sensorType != dcmi::temperatureSensorType)
1340 {
1341 log<level::ERR>("Invalid sensor type",
1342 entry("SENSOR_TYPE=%d", requestData->sensorType));
1343 return IPMI_CC_INVALID_FIELD_REQUEST;
1344 }
1345
1346 dcmi::sensor_info::ResponseList sensors{};
1347 static dcmi::Json config{};
1348 static bool parsed = false;
1349
1350 try
1351 {
1352 if (!parsed)
1353 {
Kirill Pakhomova2573622018-11-02 19:00:18 +03001354 config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001355 parsed = true;
1356 }
1357
1358 if (!requestData->entityInstance)
1359 {
1360 // Read all instances
1361 std::tie(sensors, responseData->numInstances) =
1362 dcmi::sensor_info::readAll(it->second,
Patrick Venture0b02be92018-08-31 11:55:55 -07001363 requestData->instanceStart, config);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001364 }
1365 else
1366 {
1367 // Read one instance
1368 sensors.resize(1);
1369 std::tie(sensors[0], responseData->numInstances) =
Patrick Venture0b02be92018-08-31 11:55:55 -07001370 dcmi::sensor_info::read(it->second, requestData->entityInstance,
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001371 config);
1372 }
1373 responseData->numRecords = sensors.size();
1374 }
Patrick Williamsa2ad2da2021-10-06 12:21:46 -05001375 catch (const InternalFailure& e)
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001376 {
1377 return IPMI_CC_UNSPECIFIED_ERROR;
1378 }
1379
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001380 size_t payloadSize = sensors.size() * sizeof(dcmi::sensor_info::Response);
1381 if (!sensors.empty())
1382 {
1383 memcpy(responseData + 1, // copy payload right after the response header
Patrick Venture0b02be92018-08-31 11:55:55 -07001384 sensors.data(), payloadSize);
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001385 }
1386 *data_len = sizeof(dcmi::GetSensorInfoResponseHdr) + payloadSize;
1387
1388 return IPMI_CC_OK;
1389}
1390
Chris Austen1810bec2015-10-13 12:12:39 -05001391void register_netfn_dcmi_functions()
1392{
Tom05732372016-09-06 17:21:23 +05301393 // <Get Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001394 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1395 ipmi::dcmi::cmdGetPowerLimit, ipmi::Privilege::User,
1396 getPowerLimit);
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301397
Tom Joseph46fa37d2017-07-26 18:11:55 +05301398 // <Set Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001399 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1400 ipmi::dcmi::cmdSetPowerLimit,
1401 ipmi::Privilege::Operator, setPowerLimit);
Tom Joseph46fa37d2017-07-26 18:11:55 +05301402
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301403 // <Activate/Deactivate Power Limit>
Vernon Maueryd4222fd2023-07-27 11:26:51 -07001404 registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1405 ipmi::dcmi::cmdActDeactivatePwrLimit,
1406 ipmi::Privilege::Operator, applyPowerLimit);
Tom Joseph6c8d51b2017-07-26 18:18:06 +05301407
Tom Joseph6f6dd4d2017-07-12 20:07:11 +05301408 // <Get Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301409
Patrick Venture0b02be92018-08-31 11:55:55 -07001410 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_ASSET_TAG, NULL,
1411 getAssetTag, PRIVILEGE_USER);
Tom Joseph545dd232017-07-12 20:20:49 +05301412
1413 // <Set Asset Tag>
Ratan Gupta11ddbd22017-08-05 11:59:39 +05301414
Patrick Venture0b02be92018-08-31 11:55:55 -07001415 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_ASSET_TAG, NULL,
1416 setAssetTag, PRIVILEGE_OPERATOR);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001417
Gunnar Mills8991dd62017-10-25 17:11:29 -05001418 // <Get Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001419
1420 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001421 NULL, getMgmntCtrlIdStr, PRIVILEGE_USER);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001422
1423 // <Set Management Controller Identifier String>
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001424 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_MGMNT_CTRL_ID_STR,
Patrick Venture0b02be92018-08-31 11:55:55 -07001425 NULL, setMgmntCtrlIdStr, PRIVILEGE_ADMIN);
Vladislav Vovchenko8f7a6f62017-08-17 00:31:14 +03001426
Dhruvaraj Subhashchandrane29be412018-01-16 05:11:56 -06001427 // <Get DCMI capabilities>
1428 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CAPABILITIES,
Patrick Venture0b02be92018-08-31 11:55:55 -07001429 NULL, getDCMICapabilities, PRIVILEGE_USER);
Deepak Kodihalliee717d72018-01-24 04:53:09 -06001430
1431 // <Get Temperature Readings>
1432 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_TEMP_READINGS,
1433 NULL, getTempReadings, PRIVILEGE_USER);
1434
Marri Devender Rao66c5fda2018-01-18 10:48:37 -06001435 // <Get Power Reading>
1436 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_POWER_READING,
1437 NULL, getPowerReading, PRIVILEGE_USER);
adarshgrami042e9db2022-09-15 10:34:34 +05301438// The Get sensor should get the senor details dynamically when
1439// FEATURE_DYNAMIC_SENSORS is enabled.
1440#ifndef FEATURE_DYNAMIC_SENSORS
Deepak Kodihalli0b459552018-02-06 06:25:12 -06001441 // <Get Sensor Info>
Patrick Venture0b02be92018-08-31 11:55:55 -07001442 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_SENSOR_INFO, NULL,
Chau Lyd74df5f2023-05-25 10:33:00 +00001443 getSensorInfo, PRIVILEGE_OPERATOR);
adarshgrami042e9db2022-09-15 10:34:34 +05301444#endif
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001445 // <Get DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001446 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::GET_CONF_PARAMS, NULL,
1447 getDCMIConfParams, PRIVILEGE_USER);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001448
1449 // <Set DCMI Configuration Parameters>
Patrick Venture0b02be92018-08-31 11:55:55 -07001450 ipmi_register_callback(NETFUN_GRPEXT, dcmi::Commands::SET_CONF_PARAMS, NULL,
1451 setDCMIConfParams, PRIVILEGE_ADMIN);
Nagaraju Goruganti22be97b2018-02-07 01:19:59 -06001452
Chris Austen1810bec2015-10-13 12:12:39 -05001453 return;
1454}
Tom05732372016-09-06 17:21:23 +05301455// 956379