10b02be92SPatrick Venture #include "config.h"
20b02be92SPatrick Venture
3be5eaa10STom Joseph #include "dcmihandler.hpp"
40b02be92SPatrick Venture
574a2102eSJohnathan Mantey #include "user_channel/channel_layer.hpp"
60b02be92SPatrick Venture
7e08fbffcSVernon Mauery #include <ipmid/api.hpp>
86a98fe7fSVernon Mauery #include <ipmid/utils.hpp>
90b02be92SPatrick Venture #include <nlohmann/json.hpp>
10be5eaa10STom Joseph #include <phosphor-logging/elog-errors.hpp>
117fa2871dSGeorge Liu #include <phosphor-logging/lg2.hpp>
1250c0c8fbSAndrew Geissler #include <sdbusplus/bus.hpp>
130b02be92SPatrick Venture #include <xyz/openbmc_project/Common/error.hpp>
1455cbf552SThang Tran #include <xyz/openbmc_project/Network/EthernetInterface/server.hpp>
150b02be92SPatrick Venture
16fbc6c9d7SPatrick Williams #include <bitset>
17fbc6c9d7SPatrick Williams #include <cmath>
18fbc6c9d7SPatrick Williams #include <fstream>
19fbc6c9d7SPatrick Williams #include <variant>
20fbc6c9d7SPatrick Williams
21be5eaa10STom Joseph using namespace phosphor::logging;
22523e2d1bSWilly Tu using sdbusplus::server::xyz::openbmc_project::network::EthernetInterface;
2355cbf552SThang Tran
24be5eaa10STom Joseph using InternalFailure =
25523e2d1bSWilly Tu sdbusplus::error::xyz::openbmc_project::common::InternalFailure;
2698a23840SMatthew Barth
275087b075SGeorge Liu void registerNetFnDcmiFunctions() __attribute__((constructor));
2898a23840SMatthew Barth
29d4222fd3SVernon Mauery constexpr auto pcapPath = "/xyz/openbmc_project/control/host0/power_cap";
30d4222fd3SVernon Mauery constexpr auto pcapInterface = "xyz.openbmc_project.Control.Power.Cap";
3150c0c8fbSAndrew Geissler
32d4222fd3SVernon Mauery constexpr auto powerCapProp = "PowerCap";
33d4222fd3SVernon Mauery constexpr auto powerCapEnableProp = "PowerCapEnable";
3450c0c8fbSAndrew Geissler
3550c0c8fbSAndrew Geissler using namespace phosphor::logging;
3650c0c8fbSAndrew Geissler
37b9d86f4cSTom Joseph namespace dcmi
38b9d86f4cSTom Joseph {
39dca4720fSVernon Mauery constexpr auto assetTagMaxOffset = 62;
40dca4720fSVernon Mauery constexpr auto assetTagMaxSize = 63;
41dca4720fSVernon Mauery constexpr auto maxBytes = 16;
42dca4720fSVernon Mauery constexpr size_t maxCtrlIdStrLen = 63;
43b9d86f4cSTom Joseph
44f038dc09SVernon Mauery constexpr uint8_t parameterRevision = 2;
45f038dc09SVernon Mauery constexpr uint8_t specMajorVersion = 1;
46f038dc09SVernon Mauery constexpr uint8_t specMinorVersion = 5;
47cce9ffd9SVernon Mauery constexpr auto sensorValueIntf = "xyz.openbmc_project.Sensor.Value";
48cce9ffd9SVernon Mauery constexpr auto sensorValueProp = "Value";
496475b5c9SVernon Mauery constexpr uint8_t configParameterRevision = 1;
506475b5c9SVernon Mauery constexpr auto option12Mask = 0x01;
516475b5c9SVernon Mauery constexpr auto activateDhcpReply = 0x00;
526475b5c9SVernon Mauery constexpr uint8_t dhcpTiming1 = 0x04; // 4 sec
536475b5c9SVernon Mauery constexpr uint16_t dhcpTiming2 = 0x78; // 120 sec
546475b5c9SVernon Mauery constexpr uint16_t dhcpTiming3 = 0x40; // 60 sec
556475b5c9SVernon Mauery // When DHCP Option 12 is enabled the string "SendHostName=true" will be
566475b5c9SVernon Mauery // added into n/w configuration file and the parameter
576475b5c9SVernon Mauery // SendHostNameEnabled will set to true.
586475b5c9SVernon Mauery constexpr auto dhcpOpt12Enabled = "SendHostNameEnabled";
596475b5c9SVernon Mauery
606475b5c9SVernon Mauery enum class DCMIConfigParameters : uint8_t
616475b5c9SVernon Mauery {
626475b5c9SVernon Mauery ActivateDHCP = 1,
636475b5c9SVernon Mauery DiscoveryConfig,
646475b5c9SVernon Mauery DHCPTiming1,
656475b5c9SVernon Mauery DHCPTiming2,
666475b5c9SVernon Mauery DHCPTiming3,
676475b5c9SVernon Mauery };
68f038dc09SVernon Mauery
690b45955fSDeepak Kodihalli // Refer Table 6-14, DCMI Entity ID Extension, DCMI v1.5 spec
700b02be92SPatrick Venture static const std::map<uint8_t, std::string> entityIdToName{
710b02be92SPatrick Venture {0x40, "inlet"}, {0x37, "inlet"}, {0x41, "cpu"},
720b02be92SPatrick Venture {0x03, "cpu"}, {0x42, "baseboard"}, {0x07, "baseboard"}};
730b45955fSDeepak Kodihalli
parseJSONConfig(const std::string & configFile)746475b5c9SVernon Mauery nlohmann::json parseJSONConfig(const std::string& configFile)
756475b5c9SVernon Mauery {
766475b5c9SVernon Mauery std::ifstream jsonFile(configFile);
776475b5c9SVernon Mauery if (!jsonFile.is_open())
786475b5c9SVernon Mauery {
797fa2871dSGeorge Liu lg2::error("Temperature readings JSON file not found");
806475b5c9SVernon Mauery elog<InternalFailure>();
816475b5c9SVernon Mauery }
826475b5c9SVernon Mauery
836475b5c9SVernon Mauery auto data = nlohmann::json::parse(jsonFile, nullptr, false);
846475b5c9SVernon Mauery if (data.is_discarded())
856475b5c9SVernon Mauery {
867fa2871dSGeorge Liu lg2::error("Temperature readings JSON parser failure");
876475b5c9SVernon Mauery elog<InternalFailure>();
886475b5c9SVernon Mauery }
896475b5c9SVernon Mauery
906475b5c9SVernon Mauery return data;
916475b5c9SVernon Mauery }
926475b5c9SVernon Mauery
isDCMIPowerMgmtSupported()932c2af2caSKirill Pakhomov bool isDCMIPowerMgmtSupported()
942c2af2caSKirill Pakhomov {
95f4eb35d0SVernon Mauery static bool parsed = false;
96f4eb35d0SVernon Mauery static bool supported = false;
97f4eb35d0SVernon Mauery if (!parsed)
98f4eb35d0SVernon Mauery {
992c2af2caSKirill Pakhomov auto data = parseJSONConfig(gDCMICapabilitiesConfig);
1002c2af2caSKirill Pakhomov
101f4eb35d0SVernon Mauery supported = (gDCMIPowerMgmtSupported ==
102f4eb35d0SVernon Mauery data.value(gDCMIPowerMgmtCapability, 0));
103f4eb35d0SVernon Mauery }
104f4eb35d0SVernon Mauery return supported;
1052c2af2caSKirill Pakhomov }
1062c2af2caSKirill Pakhomov
getPcap(ipmi::Context::ptr & ctx)107d4222fd3SVernon Mauery std::optional<uint32_t> getPcap(ipmi::Context::ptr& ctx)
10850c0c8fbSAndrew Geissler {
109d4222fd3SVernon Mauery std::string service{};
1101318a5edSPatrick Williams boost::system::error_code ec =
1111318a5edSPatrick Williams ipmi::getService(ctx, pcapInterface, pcapPath, service);
112d4222fd3SVernon Mauery if (ec.value())
11350c0c8fbSAndrew Geissler {
114d4222fd3SVernon Mauery return std::nullopt;
1153e3cc35bSGeorge Liu }
116d4222fd3SVernon Mauery uint32_t pcap{};
117d4222fd3SVernon Mauery ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
118d4222fd3SVernon Mauery powerCapProp, pcap);
119d4222fd3SVernon Mauery if (ec.value())
1203e3cc35bSGeorge Liu {
1217fa2871dSGeorge Liu lg2::error("Error in getPcap prop: {ERROR}", "ERROR", ec.message());
122b9d86f4cSTom Joseph elog<InternalFailure>();
123d4222fd3SVernon Mauery return std::nullopt;
12450c0c8fbSAndrew Geissler }
125d4222fd3SVernon Mauery return pcap;
12650c0c8fbSAndrew Geissler }
12750c0c8fbSAndrew Geissler
getPcapEnabled(ipmi::Context::ptr & ctx)128d4222fd3SVernon Mauery std::optional<bool> getPcapEnabled(ipmi::Context::ptr& ctx)
12950c0c8fbSAndrew Geissler {
130d4222fd3SVernon Mauery std::string service{};
1311318a5edSPatrick Williams boost::system::error_code ec =
1321318a5edSPatrick Williams ipmi::getService(ctx, pcapInterface, pcapPath, service);
133d4222fd3SVernon Mauery if (ec.value())
13450c0c8fbSAndrew Geissler {
135d4222fd3SVernon Mauery return std::nullopt;
1363e3cc35bSGeorge Liu }
137d4222fd3SVernon Mauery bool pcapEnabled{};
138d4222fd3SVernon Mauery ec = ipmi::getDbusProperty(ctx, service, pcapPath, pcapInterface,
139d4222fd3SVernon Mauery powerCapEnableProp, pcapEnabled);
140d4222fd3SVernon Mauery if (ec.value())
1413e3cc35bSGeorge Liu {
1427fa2871dSGeorge Liu lg2::error("Error in getPcap prop");
143b9d86f4cSTom Joseph elog<InternalFailure>();
144d4222fd3SVernon Mauery return std::nullopt;
14550c0c8fbSAndrew Geissler }
146d4222fd3SVernon Mauery return pcapEnabled;
14750c0c8fbSAndrew Geissler }
14898a23840SMatthew Barth
setPcap(ipmi::Context::ptr & ctx,const uint32_t powerCap)149d4222fd3SVernon Mauery bool setPcap(ipmi::Context::ptr& ctx, const uint32_t powerCap)
15046fa37d9STom Joseph {
151d4222fd3SVernon Mauery std::string service{};
1521318a5edSPatrick Williams boost::system::error_code ec =
1531318a5edSPatrick Williams ipmi::getService(ctx, pcapInterface, pcapPath, service);
154d4222fd3SVernon Mauery if (ec.value())
15546fa37d9STom Joseph {
156d4222fd3SVernon Mauery return false;
1573e3cc35bSGeorge Liu }
158d4222fd3SVernon Mauery
159d4222fd3SVernon Mauery ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
160d4222fd3SVernon Mauery powerCapProp, powerCap);
161d4222fd3SVernon Mauery if (ec.value())
1623e3cc35bSGeorge Liu {
1637fa2871dSGeorge Liu lg2::error("Error in setPcap property: {ERROR}", "ERROR", ec.message());
16446fa37d9STom Joseph elog<InternalFailure>();
165d4222fd3SVernon Mauery return false;
16646fa37d9STom Joseph }
167d4222fd3SVernon Mauery return true;
16846fa37d9STom Joseph }
16946fa37d9STom Joseph
setPcapEnable(ipmi::Context::ptr & ctx,bool enabled)170d4222fd3SVernon Mauery bool setPcapEnable(ipmi::Context::ptr& ctx, bool enabled)
1716c8d51baSTom Joseph {
172d4222fd3SVernon Mauery std::string service{};
1731318a5edSPatrick Williams boost::system::error_code ec =
1741318a5edSPatrick Williams ipmi::getService(ctx, pcapInterface, pcapPath, service);
175d4222fd3SVernon Mauery if (ec.value())
1766c8d51baSTom Joseph {
177d4222fd3SVernon Mauery return false;
1783e3cc35bSGeorge Liu }
179d4222fd3SVernon Mauery
180d4222fd3SVernon Mauery ec = ipmi::setDbusProperty(ctx, service, pcapPath, pcapInterface,
181d4222fd3SVernon Mauery powerCapEnableProp, enabled);
182d4222fd3SVernon Mauery if (ec.value())
1833e3cc35bSGeorge Liu {
1847fa2871dSGeorge Liu lg2::error("Error in setPcapEnabled property: {ERROR}", "ERROR",
1857fa2871dSGeorge Liu ec.message());
1866c8d51baSTom Joseph elog<InternalFailure>();
187d4222fd3SVernon Mauery return false;
1886c8d51baSTom Joseph }
189d4222fd3SVernon Mauery return true;
1906c8d51baSTom Joseph }
1916c8d51baSTom Joseph
readAssetTag(ipmi::Context::ptr & ctx)192dca4720fSVernon Mauery std::optional<std::string> readAssetTag(ipmi::Context::ptr& ctx)
193be5eaa10STom Joseph {
194be5eaa10STom Joseph // Read the object tree with the inventory root to figure out the object
195be5eaa10STom Joseph // that has implemented the Asset tag interface.
196dca4720fSVernon Mauery ipmi::DbusObjectInfo objectInfo;
197dca4720fSVernon Mauery boost::system::error_code ec = getDbusObject(
198dca4720fSVernon Mauery ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
199dca4720fSVernon Mauery if (ec.value())
200be5eaa10STom Joseph {
201dca4720fSVernon Mauery return std::nullopt;
2023e3cc35bSGeorge Liu }
203dca4720fSVernon Mauery
204dca4720fSVernon Mauery std::string assetTag{};
2051318a5edSPatrick Williams ec =
2061318a5edSPatrick Williams ipmi::getDbusProperty(ctx, objectInfo.second, objectInfo.first,
2071318a5edSPatrick Williams dcmi::assetTagIntf, dcmi::assetTagProp, assetTag);
208dca4720fSVernon Mauery if (ec.value())
2093e3cc35bSGeorge Liu {
2107fa2871dSGeorge Liu lg2::error("Error in reading asset tag: {ERROR}", "ERROR",
2117fa2871dSGeorge Liu ec.message());
212be5eaa10STom Joseph elog<InternalFailure>();
213dca4720fSVernon Mauery return std::nullopt;
214be5eaa10STom Joseph }
215be5eaa10STom Joseph
216dca4720fSVernon Mauery return assetTag;
217dca4720fSVernon Mauery }
218dca4720fSVernon Mauery
writeAssetTag(ipmi::Context::ptr & ctx,const std::string & assetTag)219dca4720fSVernon Mauery bool writeAssetTag(ipmi::Context::ptr& ctx, const std::string& assetTag)
220be5b9899STom Joseph {
221be5b9899STom Joseph // Read the object tree with the inventory root to figure out the object
222be5b9899STom Joseph // that has implemented the Asset tag interface.
223dca4720fSVernon Mauery ipmi::DbusObjectInfo objectInfo;
224dca4720fSVernon Mauery boost::system::error_code ec = getDbusObject(
225dca4720fSVernon Mauery ctx, dcmi::assetTagIntf, ipmi::sensor::inventoryRoot, "", objectInfo);
226dca4720fSVernon Mauery if (ec.value())
227be5b9899STom Joseph {
228dca4720fSVernon Mauery return false;
2293e3cc35bSGeorge Liu }
230dca4720fSVernon Mauery
2311318a5edSPatrick Williams ec =
2321318a5edSPatrick Williams ipmi::setDbusProperty(ctx, objectInfo.second, objectInfo.first,
2331318a5edSPatrick Williams dcmi::assetTagIntf, dcmi::assetTagProp, assetTag);
234dca4720fSVernon Mauery if (ec.value())
2353e3cc35bSGeorge Liu {
2367fa2871dSGeorge Liu lg2::error("Error in writing asset tag: {ERROR}", "ERROR",
2377fa2871dSGeorge Liu ec.message());
238be5b9899STom Joseph elog<InternalFailure>();
239dca4720fSVernon Mauery return false;
240be5b9899STom Joseph }
241dca4720fSVernon Mauery return true;
242be5b9899STom Joseph }
243be5b9899STom Joseph
getHostName(ipmi::Context::ptr & ctx)244efb5ae55SVernon Mauery std::optional<std::string> getHostName(ipmi::Context::ptr& ctx)
2458f7a6f68SVladislav Vovchenko {
246efb5ae55SVernon Mauery std::string service{};
2471318a5edSPatrick Williams boost::system::error_code ec =
2481318a5edSPatrick Williams ipmi::getService(ctx, networkConfigIntf, networkConfigObj, service);
249efb5ae55SVernon Mauery if (ec.value())
250efb5ae55SVernon Mauery {
251efb5ae55SVernon Mauery return std::nullopt;
252efb5ae55SVernon Mauery }
253efb5ae55SVernon Mauery std::string hostname{};
254efb5ae55SVernon Mauery ec = ipmi::getDbusProperty(ctx, service, networkConfigObj,
255efb5ae55SVernon Mauery networkConfigIntf, hostNameProp, hostname);
256efb5ae55SVernon Mauery if (ec.value())
257efb5ae55SVernon Mauery {
2587fa2871dSGeorge Liu lg2::error("Error fetching hostname");
259efb5ae55SVernon Mauery elog<InternalFailure>();
260efb5ae55SVernon Mauery return std::nullopt;
261efb5ae55SVernon Mauery }
262efb5ae55SVernon Mauery return hostname;
2638f7a6f68SVladislav Vovchenko }
2648f7a6f68SVladislav Vovchenko
getDHCPEnabled(ipmi::Context::ptr & ctx)265*69b4c281SPatrick Williams std::optional<EthernetInterface::DHCPConf> getDHCPEnabled(
266*69b4c281SPatrick Williams ipmi::Context::ptr& ctx)
26722be97b3SNagaraju Goruganti {
26874a2102eSJohnathan Mantey auto ethdevice = ipmi::getChannelName(ethernetDefaultChannelNum);
2696475b5c9SVernon Mauery ipmi::DbusObjectInfo ethernetObj{};
2706475b5c9SVernon Mauery boost::system::error_code ec = ipmi::getDbusObject(
2716475b5c9SVernon Mauery ctx, ethernetIntf, networkRoot, ethdevice, ethernetObj);
2726475b5c9SVernon Mauery if (ec.value())
2736475b5c9SVernon Mauery {
2746475b5c9SVernon Mauery return std::nullopt;
2756475b5c9SVernon Mauery }
2766475b5c9SVernon Mauery std::string service{};
2776475b5c9SVernon Mauery ec = ipmi::getService(ctx, ethernetIntf, ethernetObj.first, service);
2786475b5c9SVernon Mauery if (ec.value())
2796475b5c9SVernon Mauery {
2806475b5c9SVernon Mauery return std::nullopt;
2816475b5c9SVernon Mauery }
2826475b5c9SVernon Mauery std::string dhcpVal{};
2836475b5c9SVernon Mauery ec = ipmi::getDbusProperty(ctx, service, ethernetObj.first, ethernetIntf,
2846475b5c9SVernon Mauery "DHCPEnabled", dhcpVal);
2856475b5c9SVernon Mauery if (ec.value())
2866475b5c9SVernon Mauery {
2876475b5c9SVernon Mauery return std::nullopt;
28822be97b3SNagaraju Goruganti }
28922be97b3SNagaraju Goruganti
2906475b5c9SVernon Mauery return EthernetInterface::convertDHCPConfFromString(dhcpVal);
29122be97b3SNagaraju Goruganti }
29222be97b3SNagaraju Goruganti
getDHCPOption(ipmi::Context::ptr & ctx,const std::string & prop)2936475b5c9SVernon Mauery std::optional<bool> getDHCPOption(ipmi::Context::ptr& ctx,
2946475b5c9SVernon Mauery const std::string& prop)
29522be97b3SNagaraju Goruganti {
296cfd7fa83SGeorge Liu ipmi::ObjectTree objectTree;
297cfd7fa83SGeorge Liu if (ipmi::getAllDbusObjects(ctx, networkRoot, dhcpIntf, objectTree))
2986475b5c9SVernon Mauery {
2996475b5c9SVernon Mauery return std::nullopt;
30022be97b3SNagaraju Goruganti }
30122be97b3SNagaraju Goruganti
302cfd7fa83SGeorge Liu for (const auto& [path, serviceMap] : objectTree)
303cfd7fa83SGeorge Liu {
304cfd7fa83SGeorge Liu for (const auto& [service, object] : serviceMap)
305cfd7fa83SGeorge Liu {
306cfd7fa83SGeorge Liu bool value{};
307cfd7fa83SGeorge Liu if (ipmi::getDbusProperty(ctx, service, path, dhcpIntf, prop,
308cfd7fa83SGeorge Liu value))
309cfd7fa83SGeorge Liu {
310cfd7fa83SGeorge Liu return std::nullopt;
311cfd7fa83SGeorge Liu }
312cfd7fa83SGeorge Liu
313cfd7fa83SGeorge Liu if (value)
314cfd7fa83SGeorge Liu {
315cfd7fa83SGeorge Liu return true;
316cfd7fa83SGeorge Liu }
317cfd7fa83SGeorge Liu }
318cfd7fa83SGeorge Liu }
319cfd7fa83SGeorge Liu
320cfd7fa83SGeorge Liu return false;
3210b45955fSDeepak Kodihalli }
3220b45955fSDeepak Kodihalli
setDHCPOption(ipmi::Context::ptr & ctx,std::string prop,bool value)3236475b5c9SVernon Mauery bool setDHCPOption(ipmi::Context::ptr& ctx, std::string prop, bool value)
3240b45955fSDeepak Kodihalli {
325cfd7fa83SGeorge Liu ipmi::ObjectTree objectTree;
326cfd7fa83SGeorge Liu if (ipmi::getAllDbusObjects(ctx, networkRoot, dhcpIntf, objectTree))
3276475b5c9SVernon Mauery {
328cfd7fa83SGeorge Liu return false;
3290b45955fSDeepak Kodihalli }
330cfd7fa83SGeorge Liu
331cfd7fa83SGeorge Liu for (const auto& [path, serviceMap] : objectTree)
332cfd7fa83SGeorge Liu {
333cfd7fa83SGeorge Liu for (const auto& [service, object] : serviceMap)
334cfd7fa83SGeorge Liu {
335cfd7fa83SGeorge Liu if (ipmi::setDbusProperty(ctx, service, path, dhcpIntf, prop,
336cfd7fa83SGeorge Liu value))
337cfd7fa83SGeorge Liu {
338cfd7fa83SGeorge Liu return false;
339cfd7fa83SGeorge Liu }
340cfd7fa83SGeorge Liu }
341cfd7fa83SGeorge Liu }
342cfd7fa83SGeorge Liu
343cfd7fa83SGeorge Liu return true;
3440b45955fSDeepak Kodihalli }
3450b45955fSDeepak Kodihalli
346be5eaa10STom Joseph } // namespace dcmi
34798a23840SMatthew Barth
348d4222fd3SVernon Mauery constexpr uint8_t exceptionPowerOff = 0x01;
349d4222fd3SVernon Mauery ipmi::RspType<uint16_t, // reserved
350d4222fd3SVernon Mauery uint8_t, // exception actions
351d4222fd3SVernon Mauery uint16_t, // power limit requested in watts
352d4222fd3SVernon Mauery uint32_t, // correction time in milliseconds
353d4222fd3SVernon Mauery uint16_t, // reserved
354d4222fd3SVernon Mauery uint16_t // statistics sampling period in seconds
355d4222fd3SVernon Mauery >
getPowerLimit(ipmi::Context::ptr ctx,uint16_t reserved)356d4222fd3SVernon Mauery getPowerLimit(ipmi::Context::ptr ctx, uint16_t reserved)
357b9d86f4cSTom Joseph {
3582c2af2caSKirill Pakhomov if (!dcmi::isDCMIPowerMgmtSupported())
3592c2af2caSKirill Pakhomov {
360d4222fd3SVernon Mauery return ipmi::responseInvalidCommand();
3612c2af2caSKirill Pakhomov }
362d4222fd3SVernon Mauery if (reserved)
363b9d86f4cSTom Joseph {
364d4222fd3SVernon Mauery return ipmi::responseInvalidFieldRequest();
365b9d86f4cSTom Joseph }
366b9d86f4cSTom Joseph
367d4222fd3SVernon Mauery std::optional<uint16_t> pcapValue = dcmi::getPcap(ctx);
368d4222fd3SVernon Mauery std::optional<bool> pcapEnable = dcmi::getPcapEnabled(ctx);
369d4222fd3SVernon Mauery if (!pcapValue || !pcapEnable)
370d4222fd3SVernon Mauery {
371d4222fd3SVernon Mauery return ipmi::responseUnspecifiedError();
372d4222fd3SVernon Mauery }
373d4222fd3SVernon Mauery
374d4222fd3SVernon Mauery constexpr uint16_t reserved1{};
375d4222fd3SVernon Mauery constexpr uint16_t reserved2{};
376b9d86f4cSTom Joseph /*
377b9d86f4cSTom Joseph * Exception action if power limit is exceeded and cannot be controlled
378b9d86f4cSTom Joseph * with the correction time limit is hardcoded to Hard Power Off system
379b9d86f4cSTom Joseph * and log event to SEL.
380b9d86f4cSTom Joseph */
381d4222fd3SVernon Mauery constexpr uint8_t exception = exceptionPowerOff;
382b9d86f4cSTom Joseph /*
383b9d86f4cSTom Joseph * Correction time limit and Statistics sampling period is currently not
384b9d86f4cSTom Joseph * populated.
385b9d86f4cSTom Joseph */
386d4222fd3SVernon Mauery constexpr uint32_t correctionTime{};
387d4222fd3SVernon Mauery constexpr uint16_t statsPeriod{};
388fd9c3617SThang Tran if (*pcapEnable == false)
389b9d86f4cSTom Joseph {
390d4222fd3SVernon Mauery constexpr ipmi::Cc responseNoPowerLimitSet = 0x80;
391d4222fd3SVernon Mauery return ipmi::response(responseNoPowerLimitSet, reserved1, exception,
392fd9c3617SThang Tran *pcapValue, correctionTime, reserved2,
393fd9c3617SThang Tran statsPeriod);
394b9d86f4cSTom Joseph }
395d4222fd3SVernon Mauery return ipmi::responseSuccess(reserved1, exception, *pcapValue,
396d4222fd3SVernon Mauery correctionTime, reserved2, statsPeriod);
397b9d86f4cSTom Joseph }
398b9d86f4cSTom Joseph
setPowerLimit(ipmi::Context::ptr & ctx,uint16_t reserved1,uint8_t reserved2,uint8_t exceptionAction,uint16_t powerLimit,uint32_t correctionTime,uint16_t reserved3,uint16_t statsPeriod)399d4222fd3SVernon Mauery ipmi::RspType<> setPowerLimit(ipmi::Context::ptr& ctx, uint16_t reserved1,
400fd9c3617SThang Tran uint8_t reserved2, uint8_t exceptionAction,
401fd9c3617SThang Tran uint16_t powerLimit, uint32_t correctionTime,
402fd9c3617SThang Tran uint16_t reserved3, uint16_t statsPeriod)
40346fa37d9STom Joseph {
4042c2af2caSKirill Pakhomov if (!dcmi::isDCMIPowerMgmtSupported())
4052c2af2caSKirill Pakhomov {
4067fa2871dSGeorge Liu lg2::error("DCMI Power management is unsupported!");
407d4222fd3SVernon Mauery return ipmi::responseInvalidCommand();
4082c2af2caSKirill Pakhomov }
4092c2af2caSKirill Pakhomov
410d4222fd3SVernon Mauery // Only process the power limit requested in watts. Return errors
411d4222fd3SVernon Mauery // for other fields that are set
412fd9c3617SThang Tran if (reserved1 || reserved2 || reserved3 || correctionTime || statsPeriod ||
413d4222fd3SVernon Mauery exceptionAction != exceptionPowerOff)
41446fa37d9STom Joseph {
415d4222fd3SVernon Mauery return ipmi::responseInvalidFieldRequest();
41646fa37d9STom Joseph }
417d4222fd3SVernon Mauery
418d4222fd3SVernon Mauery if (!dcmi::setPcap(ctx, powerLimit))
41946fa37d9STom Joseph {
420d4222fd3SVernon Mauery return ipmi::responseUnspecifiedError();
42146fa37d9STom Joseph }
42246fa37d9STom Joseph
4237fa2871dSGeorge Liu lg2::info("Set Power Cap: {POWERCAP}", "POWERCAP", powerLimit);
42446fa37d9STom Joseph
425d4222fd3SVernon Mauery return ipmi::responseSuccess();
42646fa37d9STom Joseph }
42746fa37d9STom Joseph
applyPowerLimit(ipmi::Context::ptr & ctx,bool enabled,uint7_t reserved1,uint16_t reserved2)428d4222fd3SVernon Mauery ipmi::RspType<> applyPowerLimit(ipmi::Context::ptr& ctx, bool enabled,
429d4222fd3SVernon Mauery uint7_t reserved1, uint16_t reserved2)
4306c8d51baSTom Joseph {
4312c2af2caSKirill Pakhomov if (!dcmi::isDCMIPowerMgmtSupported())
4322c2af2caSKirill Pakhomov {
4337fa2871dSGeorge Liu lg2::error("DCMI Power management is unsupported!");
434d4222fd3SVernon Mauery return ipmi::responseInvalidCommand();
435d4222fd3SVernon Mauery }
436d4222fd3SVernon Mauery if (reserved1 || reserved2)
437d4222fd3SVernon Mauery {
438d4222fd3SVernon Mauery return ipmi::responseInvalidFieldRequest();
4392c2af2caSKirill Pakhomov }
4402c2af2caSKirill Pakhomov
441d4222fd3SVernon Mauery if (!dcmi::setPcapEnable(ctx, enabled))
4426c8d51baSTom Joseph {
443d4222fd3SVernon Mauery return ipmi::responseUnspecifiedError();
4446c8d51baSTom Joseph }
4456c8d51baSTom Joseph
4467fa2871dSGeorge Liu lg2::info("Set Power Cap Enable: {POWERCAPENABLE}", "POWERCAPENABLE",
4477fa2871dSGeorge Liu enabled);
4486c8d51baSTom Joseph
449d4222fd3SVernon Mauery return ipmi::responseSuccess();
4506c8d51baSTom Joseph }
4516c8d51baSTom Joseph
452dca4720fSVernon Mauery ipmi::RspType<uint8_t, // total tag length
453dca4720fSVernon Mauery std::vector<char> // tag data
454dca4720fSVernon Mauery >
getAssetTag(ipmi::Context::ptr & ctx,uint8_t offset,uint8_t count)455dca4720fSVernon Mauery getAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
4566f6dd4d7STom Joseph {
457dca4720fSVernon Mauery // Verify offset to read and number of bytes to read are not exceeding
458dca4720fSVernon Mauery // the range.
459dca4720fSVernon Mauery if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
460dca4720fSVernon Mauery ((offset + count) > dcmi::assetTagMaxSize))
4616f6dd4d7STom Joseph {
462dca4720fSVernon Mauery return ipmi::responseParmOutOfRange();
4636f6dd4d7STom Joseph }
4646f6dd4d7STom Joseph
465dca4720fSVernon Mauery std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
466dca4720fSVernon Mauery if (!assetTagResp)
4676f6dd4d7STom Joseph {
468dca4720fSVernon Mauery return ipmi::responseUnspecifiedError();
4696f6dd4d7STom Joseph }
4706f6dd4d7STom Joseph
471dca4720fSVernon Mauery std::string& assetTag = assetTagResp.value();
472dca4720fSVernon Mauery // If the asset tag is longer than 63 bytes, restrict it to 63 bytes to
473dca4720fSVernon Mauery // suit Get Asset Tag command.
4746f6dd4d7STom Joseph if (assetTag.size() > dcmi::assetTagMaxSize)
4756f6dd4d7STom Joseph {
4766f6dd4d7STom Joseph assetTag.resize(dcmi::assetTagMaxSize);
4776f6dd4d7STom Joseph }
4786f6dd4d7STom Joseph
479dca4720fSVernon Mauery if (offset >= assetTag.size())
4806f6dd4d7STom Joseph {
481dca4720fSVernon Mauery return ipmi::responseParmOutOfRange();
4826f6dd4d7STom Joseph }
4836f6dd4d7STom Joseph
484dca4720fSVernon Mauery // silently truncate reads beyond the end of assetTag
485dca4720fSVernon Mauery if ((offset + count) >= assetTag.size())
486dca4720fSVernon Mauery {
487dca4720fSVernon Mauery count = assetTag.size() - offset;
4886f6dd4d7STom Joseph }
4896f6dd4d7STom Joseph
490dca4720fSVernon Mauery auto totalTagSize = static_cast<uint8_t>(assetTag.size());
491dca4720fSVernon Mauery std::vector<char> data{assetTag.begin() + offset,
492dca4720fSVernon Mauery assetTag.begin() + offset + count};
493545dd232STom Joseph
494dca4720fSVernon Mauery return ipmi::responseSuccess(totalTagSize, data);
495545dd232STom Joseph }
496545dd232STom Joseph
497dca4720fSVernon Mauery ipmi::RspType<uint8_t // new asset tag length
498dca4720fSVernon Mauery >
setAssetTag(ipmi::Context::ptr & ctx,uint8_t offset,uint8_t count,const std::vector<char> & data)499dca4720fSVernon Mauery setAssetTag(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count,
500dca4720fSVernon Mauery const std::vector<char>& data)
501545dd232STom Joseph {
502dca4720fSVernon Mauery // Verify offset to read and number of bytes to read are not exceeding
503dca4720fSVernon Mauery // the range.
504dca4720fSVernon Mauery if ((offset > dcmi::assetTagMaxOffset) || (count > dcmi::maxBytes) ||
505dca4720fSVernon Mauery ((offset + count) > dcmi::assetTagMaxSize))
506545dd232STom Joseph {
507dca4720fSVernon Mauery return ipmi::responseParmOutOfRange();
508dca4720fSVernon Mauery }
509dca4720fSVernon Mauery if (data.size() != count)
510dca4720fSVernon Mauery {
511dca4720fSVernon Mauery return ipmi::responseReqDataLenInvalid();
512545dd232STom Joseph }
513545dd232STom Joseph
514dca4720fSVernon Mauery std::optional<std::string> assetTagResp = dcmi::readAssetTag(ctx);
515dca4720fSVernon Mauery if (!assetTagResp)
516545dd232STom Joseph {
517dca4720fSVernon Mauery return ipmi::responseUnspecifiedError();
518545dd232STom Joseph }
519dca4720fSVernon Mauery
520dca4720fSVernon Mauery std::string& assetTag = assetTagResp.value();
521dca4720fSVernon Mauery
522dca4720fSVernon Mauery if (offset > assetTag.size())
523dca4720fSVernon Mauery {
524dca4720fSVernon Mauery return ipmi::responseParmOutOfRange();
525dca4720fSVernon Mauery }
526dca4720fSVernon Mauery
527dca4720fSVernon Mauery // operation is to truncate at offset and append new data
528dca4720fSVernon Mauery assetTag.resize(offset);
529dca4720fSVernon Mauery assetTag.append(data.begin(), data.end());
530dca4720fSVernon Mauery
531dca4720fSVernon Mauery if (!dcmi::writeAssetTag(ctx, assetTag))
532dca4720fSVernon Mauery {
533dca4720fSVernon Mauery return ipmi::responseUnspecifiedError();
534dca4720fSVernon Mauery }
535dca4720fSVernon Mauery
536dca4720fSVernon Mauery auto totalTagSize = static_cast<uint8_t>(assetTag.size());
537dca4720fSVernon Mauery return ipmi::responseSuccess(totalTagSize);
538545dd232STom Joseph }
539545dd232STom Joseph
540efb5ae55SVernon Mauery ipmi::RspType<uint8_t, // length
541efb5ae55SVernon Mauery std::vector<char> // data
542efb5ae55SVernon Mauery >
getMgmntCtrlIdStr(ipmi::Context::ptr & ctx,uint8_t offset,uint8_t count)543efb5ae55SVernon Mauery getMgmntCtrlIdStr(ipmi::Context::ptr& ctx, uint8_t offset, uint8_t count)
5448f7a6f68SVladislav Vovchenko {
545efb5ae55SVernon Mauery if (count > dcmi::maxBytes || offset + count > dcmi::maxCtrlIdStrLen)
5468f7a6f68SVladislav Vovchenko {
547efb5ae55SVernon Mauery return ipmi::responseParmOutOfRange();
5488f7a6f68SVladislav Vovchenko }
5498f7a6f68SVladislav Vovchenko
550efb5ae55SVernon Mauery std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
551efb5ae55SVernon Mauery if (!hostnameResp)
5528f7a6f68SVladislav Vovchenko {
553efb5ae55SVernon Mauery return ipmi::responseUnspecifiedError();
5548f7a6f68SVladislav Vovchenko }
5558f7a6f68SVladislav Vovchenko
556efb5ae55SVernon Mauery std::string& hostname = hostnameResp.value();
557efb5ae55SVernon Mauery // If the id string is longer than 63 bytes, restrict it to 63 bytes to
558efb5ae55SVernon Mauery // suit set management ctrl str command.
559efb5ae55SVernon Mauery if (hostname.size() > dcmi::maxCtrlIdStrLen)
5608f7a6f68SVladislav Vovchenko {
561efb5ae55SVernon Mauery hostname.resize(dcmi::maxCtrlIdStrLen);
5628f7a6f68SVladislav Vovchenko }
5638f7a6f68SVladislav Vovchenko
564efb5ae55SVernon Mauery if (offset >= hostname.size())
5658f7a6f68SVladislav Vovchenko {
566efb5ae55SVernon Mauery return ipmi::responseParmOutOfRange();
5678f7a6f68SVladislav Vovchenko }
5688f7a6f68SVladislav Vovchenko
569efb5ae55SVernon Mauery // silently truncate reads beyond the end of hostname
570efb5ae55SVernon Mauery if ((offset + count) >= hostname.size())
5718f7a6f68SVladislav Vovchenko {
572efb5ae55SVernon Mauery count = hostname.size() - offset;
573efb5ae55SVernon Mauery }
574efb5ae55SVernon Mauery
575efb5ae55SVernon Mauery auto nameSize = static_cast<uint8_t>(hostname.size());
576efb5ae55SVernon Mauery std::vector<char> data{hostname.begin() + offset,
577efb5ae55SVernon Mauery hostname.begin() + offset + count};
578efb5ae55SVernon Mauery
579efb5ae55SVernon Mauery return ipmi::responseSuccess(nameSize, data);
580efb5ae55SVernon Mauery }
581efb5ae55SVernon Mauery
setMgmntCtrlIdStr(ipmi::Context::ptr & ctx,uint8_t offset,uint8_t count,std::vector<char> data)582*69b4c281SPatrick Williams ipmi::RspType<uint8_t> setMgmntCtrlIdStr(ipmi::Context::ptr& ctx,
583*69b4c281SPatrick Williams uint8_t offset, uint8_t count,
584efb5ae55SVernon Mauery std::vector<char> data)
585efb5ae55SVernon Mauery {
586efb5ae55SVernon Mauery if ((offset > dcmi::maxCtrlIdStrLen) || (count > dcmi::maxBytes) ||
587efb5ae55SVernon Mauery ((offset + count) > dcmi::maxCtrlIdStrLen))
588efb5ae55SVernon Mauery {
589efb5ae55SVernon Mauery return ipmi::responseParmOutOfRange();
590efb5ae55SVernon Mauery }
591efb5ae55SVernon Mauery if (data.size() != count)
592efb5ae55SVernon Mauery {
593efb5ae55SVernon Mauery return ipmi::responseReqDataLenInvalid();
594efb5ae55SVernon Mauery }
595efb5ae55SVernon Mauery bool terminalWrite{data.back() == '\0'};
596efb5ae55SVernon Mauery if (terminalWrite)
597efb5ae55SVernon Mauery {
598efb5ae55SVernon Mauery // remove the null termination from the data (no need with std::string)
599efb5ae55SVernon Mauery data.resize(count - 1);
600efb5ae55SVernon Mauery }
601efb5ae55SVernon Mauery
602efb5ae55SVernon Mauery static std::string hostname{};
603efb5ae55SVernon Mauery // read in the current value if not starting at offset 0
604efb5ae55SVernon Mauery if (hostname.size() == 0 && offset != 0)
6058f7a6f68SVladislav Vovchenko {
6068f7a6f68SVladislav Vovchenko /* read old ctrlIdStr */
607efb5ae55SVernon Mauery std::optional<std::string> hostnameResp = dcmi::getHostName(ctx);
608efb5ae55SVernon Mauery if (!hostnameResp)
609efb5ae55SVernon Mauery {
610efb5ae55SVernon Mauery return ipmi::responseUnspecifiedError();
611efb5ae55SVernon Mauery }
612efb5ae55SVernon Mauery hostname = hostnameResp.value();
613efb5ae55SVernon Mauery hostname.resize(offset);
6148f7a6f68SVladislav Vovchenko }
6158f7a6f68SVladislav Vovchenko
616efb5ae55SVernon Mauery // operation is to truncate at offset and append new data
617efb5ae55SVernon Mauery hostname.append(data.begin(), data.end());
618efb5ae55SVernon Mauery
619efb5ae55SVernon Mauery // do the update if this is the last write
620efb5ae55SVernon Mauery if (terminalWrite)
6218f7a6f68SVladislav Vovchenko {
622efb5ae55SVernon Mauery boost::system::error_code ec = ipmi::setDbusProperty(
623efb5ae55SVernon Mauery ctx, dcmi::networkServiceName, dcmi::networkConfigObj,
624efb5ae55SVernon Mauery dcmi::networkConfigIntf, dcmi::hostNameProp, hostname);
625efb5ae55SVernon Mauery hostname.clear();
626efb5ae55SVernon Mauery if (ec.value())
627efb5ae55SVernon Mauery {
628efb5ae55SVernon Mauery return ipmi::responseUnspecifiedError();
629efb5ae55SVernon Mauery }
6308f7a6f68SVladislav Vovchenko }
6318f7a6f68SVladislav Vovchenko
632efb5ae55SVernon Mauery auto totalIdSize = static_cast<uint8_t>(offset + count);
633efb5ae55SVernon Mauery return ipmi::responseSuccess(totalIdSize);
6348f7a6f68SVladislav Vovchenko }
6358f7a6f68SVladislav Vovchenko
getDCMICapabilities(uint8_t parameter)636f038dc09SVernon Mauery ipmi::RspType<ipmi::message::Payload> getDCMICapabilities(uint8_t parameter)
637e29be41fSDhruvaraj Subhashchandran {
638a2573622SKirill Pakhomov std::ifstream dcmiCapFile(dcmi::gDCMICapabilitiesConfig);
639e29be41fSDhruvaraj Subhashchandran if (!dcmiCapFile.is_open())
640e29be41fSDhruvaraj Subhashchandran {
6417fa2871dSGeorge Liu lg2::error("DCMI Capabilities file not found");
642f038dc09SVernon Mauery return ipmi::responseUnspecifiedError();
643e29be41fSDhruvaraj Subhashchandran }
644e29be41fSDhruvaraj Subhashchandran
645e29be41fSDhruvaraj Subhashchandran auto data = nlohmann::json::parse(dcmiCapFile, nullptr, false);
646e29be41fSDhruvaraj Subhashchandran if (data.is_discarded())
647e29be41fSDhruvaraj Subhashchandran {
6487fa2871dSGeorge Liu lg2::error("DCMI Capabilities JSON parser failure");
649f038dc09SVernon Mauery return ipmi::responseUnspecifiedError();
650e29be41fSDhruvaraj Subhashchandran }
651e29be41fSDhruvaraj Subhashchandran
652f038dc09SVernon Mauery constexpr bool reserved1{};
653f038dc09SVernon Mauery constexpr uint5_t reserved5{};
654f038dc09SVernon Mauery constexpr uint7_t reserved7{};
655f038dc09SVernon Mauery constexpr uint8_t reserved8{};
656f038dc09SVernon Mauery constexpr uint16_t reserved16{};
657e29be41fSDhruvaraj Subhashchandran
658f038dc09SVernon Mauery ipmi::message::Payload payload;
659f038dc09SVernon Mauery payload.pack(dcmi::specMajorVersion, dcmi::specMinorVersion,
660f038dc09SVernon Mauery dcmi::parameterRevision);
661f038dc09SVernon Mauery
662f038dc09SVernon Mauery enum class DCMICapParameters : uint8_t
663f038dc09SVernon Mauery {
664f038dc09SVernon Mauery SupportedDcmiCaps = 0x01, // Supported DCMI Capabilities
665f038dc09SVernon Mauery MandatoryPlatAttributes = 0x02, // Mandatory Platform Attributes
666f038dc09SVernon Mauery OptionalPlatAttributes = 0x03, // Optional Platform Attributes
667f038dc09SVernon Mauery ManageabilityAccessAttributes = 0x04, // Manageability Access Attributes
668f038dc09SVernon Mauery };
669f038dc09SVernon Mauery
670f038dc09SVernon Mauery switch (static_cast<DCMICapParameters>(parameter))
671f038dc09SVernon Mauery {
672f038dc09SVernon Mauery case DCMICapParameters::SupportedDcmiCaps:
673f038dc09SVernon Mauery {
674f038dc09SVernon Mauery bool powerManagement = data.value("PowerManagement", 0);
675f038dc09SVernon Mauery bool oobSecondaryLan = data.value("OOBSecondaryLan", 0);
676f038dc09SVernon Mauery bool serialTMode = data.value("SerialTMODE", 0);
677f038dc09SVernon Mauery bool inBandSystemInterfaceChannel =
678f038dc09SVernon Mauery data.value("InBandSystemInterfaceChannel", 0);
679f038dc09SVernon Mauery payload.pack(reserved8, powerManagement, reserved7,
680f038dc09SVernon Mauery inBandSystemInterfaceChannel, serialTMode,
681f038dc09SVernon Mauery oobSecondaryLan, reserved5);
682f038dc09SVernon Mauery break;
683f038dc09SVernon Mauery }
684f038dc09SVernon Mauery // Mandatory Platform Attributes
685f038dc09SVernon Mauery case DCMICapParameters::MandatoryPlatAttributes:
686f038dc09SVernon Mauery {
687f038dc09SVernon Mauery bool selAutoRollOver = data.value("SELAutoRollOver", 0);
688f038dc09SVernon Mauery bool flushEntireSELUponRollOver =
689f038dc09SVernon Mauery data.value("FlushEntireSELUponRollOver", 0);
690f038dc09SVernon Mauery bool recordLevelSELFlushUponRollOver =
691f038dc09SVernon Mauery data.value("RecordLevelSELFlushUponRollOver", 0);
6921318a5edSPatrick Williams uint12_t numberOfSELEntries =
6931318a5edSPatrick Williams data.value("NumberOfSELEntries", 0xcac);
694f038dc09SVernon Mauery uint8_t tempMonitoringSamplingFreq =
695f038dc09SVernon Mauery data.value("TempMonitoringSamplingFreq", 0);
696f038dc09SVernon Mauery payload.pack(numberOfSELEntries, reserved1,
697f038dc09SVernon Mauery recordLevelSELFlushUponRollOver,
698f038dc09SVernon Mauery flushEntireSELUponRollOver, selAutoRollOver,
699f038dc09SVernon Mauery reserved16, tempMonitoringSamplingFreq);
700f038dc09SVernon Mauery break;
701f038dc09SVernon Mauery }
702f038dc09SVernon Mauery // Optional Platform Attributes
703f038dc09SVernon Mauery case DCMICapParameters::OptionalPlatAttributes:
704f038dc09SVernon Mauery {
70568d9d405SMatt Simmering uint7_t powerMgmtDeviceTargetAddress =
706f038dc09SVernon Mauery data.value("PowerMgmtDeviceSlaveAddress", 0);
707f038dc09SVernon Mauery uint4_t bmcChannelNumber = data.value("BMCChannelNumber", 0);
708f038dc09SVernon Mauery uint4_t deviceRivision = data.value("DeviceRivision", 0);
70968d9d405SMatt Simmering payload.pack(powerMgmtDeviceTargetAddress, reserved1,
71068d9d405SMatt Simmering deviceRivision, bmcChannelNumber);
711f038dc09SVernon Mauery break;
712f038dc09SVernon Mauery }
713f038dc09SVernon Mauery // Manageability Access Attributes
714f038dc09SVernon Mauery case DCMICapParameters::ManageabilityAccessAttributes:
715f038dc09SVernon Mauery {
716f038dc09SVernon Mauery uint8_t mandatoryPrimaryLanOOBSupport =
717f038dc09SVernon Mauery data.value("MandatoryPrimaryLanOOBSupport", 0xff);
718f038dc09SVernon Mauery uint8_t optionalSecondaryLanOOBSupport =
719f038dc09SVernon Mauery data.value("OptionalSecondaryLanOOBSupport", 0xff);
720f038dc09SVernon Mauery uint8_t optionalSerialOOBMTMODECapability =
721f038dc09SVernon Mauery data.value("OptionalSerialOOBMTMODECapability", 0xff);
722f038dc09SVernon Mauery payload.pack(mandatoryPrimaryLanOOBSupport,
723f038dc09SVernon Mauery optionalSecondaryLanOOBSupport,
724f038dc09SVernon Mauery optionalSerialOOBMTMODECapability);
725f038dc09SVernon Mauery break;
726f038dc09SVernon Mauery }
727f038dc09SVernon Mauery default:
728e29be41fSDhruvaraj Subhashchandran {
7297fa2871dSGeorge Liu lg2::error("Invalid input parameter");
730f038dc09SVernon Mauery return ipmi::responseInvalidFieldRequest();
731e29be41fSDhruvaraj Subhashchandran }
732e29be41fSDhruvaraj Subhashchandran }
733e29be41fSDhruvaraj Subhashchandran
734f038dc09SVernon Mauery return ipmi::responseSuccess(payload);
735e29be41fSDhruvaraj Subhashchandran }
736e29be41fSDhruvaraj Subhashchandran
737ee717d71SDeepak Kodihalli namespace dcmi
738ee717d71SDeepak Kodihalli {
739ee717d71SDeepak Kodihalli namespace temp_readings
740ee717d71SDeepak Kodihalli {
741ee717d71SDeepak Kodihalli
readTemp(ipmi::Context::ptr & ctx,const std::string & dbusService,const std::string & dbusPath)742*69b4c281SPatrick Williams std::tuple<bool, bool, uint8_t> readTemp(ipmi::Context::ptr& ctx,
743*69b4c281SPatrick Williams const std::string& dbusService,
744b1e8fba5SDeepak Kodihalli const std::string& dbusPath)
745b1e8fba5SDeepak Kodihalli {
746b1e8fba5SDeepak Kodihalli // Read the temperature value from d-bus object. Need some conversion.
747cce9ffd9SVernon Mauery // As per the interface xyz.openbmc_project.Sensor.Value, the
748cce9ffd9SVernon Mauery // temperature is an double and in degrees C. It needs to be scaled by
749cce9ffd9SVernon Mauery // using the formula Value * 10^Scale. The ipmi spec has the temperature
750cce9ffd9SVernon Mauery // as a uint8_t, with a separate single bit for the sign.
751b1e8fba5SDeepak Kodihalli
752cce9ffd9SVernon Mauery ipmi::PropertyMap result{};
753cce9ffd9SVernon Mauery boost::system::error_code ec = ipmi::getAllDbusProperties(
754cce9ffd9SVernon Mauery ctx, dbusService, dbusPath, "xyz.openbmc_project.Sensor.Value", result);
755cce9ffd9SVernon Mauery if (ec.value())
756cce9ffd9SVernon Mauery {
757cce9ffd9SVernon Mauery return std::make_tuple(false, false, 0);
758cce9ffd9SVernon Mauery }
7591318a5edSPatrick Williams auto temperature =
7601318a5edSPatrick Williams std::visit(ipmi::VariantToDoubleVisitor(), result.at("Value"));
7619cc0ea5fSJames Feist double absTemp = std::abs(temperature);
762b1e8fba5SDeepak Kodihalli
7639cc0ea5fSJames Feist auto findFactor = result.find("Scale");
7649cc0ea5fSJames Feist double factor = 0.0;
7659cc0ea5fSJames Feist if (findFactor != result.end())
766b1e8fba5SDeepak Kodihalli {
767f442e119SVernon Mauery factor = std::visit(ipmi::VariantToDoubleVisitor(), findFactor->second);
768b1e8fba5SDeepak Kodihalli }
7699cc0ea5fSJames Feist double scale = std::pow(10, factor);
7709cc0ea5fSJames Feist
7719cc0ea5fSJames Feist auto tempDegrees = absTemp * scale;
772cce9ffd9SVernon Mauery // Max absolute temp as per ipmi spec is 127.
773cce9ffd9SVernon Mauery constexpr auto maxTemp = 127;
774b1e8fba5SDeepak Kodihalli if (tempDegrees > maxTemp)
775b1e8fba5SDeepak Kodihalli {
776b1e8fba5SDeepak Kodihalli tempDegrees = maxTemp;
777b1e8fba5SDeepak Kodihalli }
778b1e8fba5SDeepak Kodihalli
779cce9ffd9SVernon Mauery return std::make_tuple(true, (temperature < 0),
780cce9ffd9SVernon Mauery static_cast<uint8_t>(tempDegrees));
781b1e8fba5SDeepak Kodihalli }
782b1e8fba5SDeepak Kodihalli
read(ipmi::Context::ptr & ctx,const std::string & type,uint8_t instance,size_t count)783*69b4c281SPatrick Williams std::tuple<std::vector<std::tuple<uint7_t, bool, uint8_t>>, uint8_t> read(
784*69b4c281SPatrick Williams ipmi::Context::ptr& ctx, const std::string& type, uint8_t instance,
785cce9ffd9SVernon Mauery size_t count)
786ee717d71SDeepak Kodihalli {
787cce9ffd9SVernon Mauery std::vector<std::tuple<uint7_t, bool, uint8_t>> response{};
788b1e8fba5SDeepak Kodihalli
789a2573622SKirill Pakhomov auto data = parseJSONConfig(gDCMISensorsConfig);
790cce9ffd9SVernon Mauery static const std::vector<nlohmann::json> empty{};
791cce9ffd9SVernon Mauery std::vector<nlohmann::json> readings = data.value(type, empty);
792b1e8fba5SDeepak Kodihalli for (const auto& j : readings)
793b1e8fba5SDeepak Kodihalli {
794b1e8fba5SDeepak Kodihalli // Max of 8 response data sets
795cce9ffd9SVernon Mauery if (response.size() == count)
796b1e8fba5SDeepak Kodihalli {
797b1e8fba5SDeepak Kodihalli break;
798b1e8fba5SDeepak Kodihalli }
799b1e8fba5SDeepak Kodihalli
800b1e8fba5SDeepak Kodihalli uint8_t instanceNum = j.value("instance", 0);
801b1e8fba5SDeepak Kodihalli // Not in the instance range we're interested in
802cce9ffd9SVernon Mauery if (instanceNum < instance)
803b1e8fba5SDeepak Kodihalli {
804b1e8fba5SDeepak Kodihalli continue;
805b1e8fba5SDeepak Kodihalli }
806b1e8fba5SDeepak Kodihalli
807b1e8fba5SDeepak Kodihalli std::string path = j.value("dbus", "");
808cce9ffd9SVernon Mauery std::string service{};
809cce9ffd9SVernon Mauery boost::system::error_code ec = ipmi::getService(
810cce9ffd9SVernon Mauery ctx, "xyz.openbmc_project.Sensor.Value", path, service);
811cce9ffd9SVernon Mauery if (ec.value())
812b1e8fba5SDeepak Kodihalli {
813cce9ffd9SVernon Mauery // not found on dbus
814b1e8fba5SDeepak Kodihalli continue;
815b1e8fba5SDeepak Kodihalli }
816cce9ffd9SVernon Mauery
817cce9ffd9SVernon Mauery const auto& [ok, sign, temp] = readTemp(ctx, service, path);
818cce9ffd9SVernon Mauery if (ok)
819cce9ffd9SVernon Mauery {
820cce9ffd9SVernon Mauery response.emplace_back(uint7_t{temp}, sign, instanceNum);
821cce9ffd9SVernon Mauery }
822b1e8fba5SDeepak Kodihalli }
823b1e8fba5SDeepak Kodihalli
824cce9ffd9SVernon Mauery auto totalInstances =
825cce9ffd9SVernon Mauery static_cast<uint8_t>(std::min(readings.size(), maxInstances));
826cce9ffd9SVernon Mauery return std::make_tuple(response, totalInstances);
827ee717d71SDeepak Kodihalli }
828ee717d71SDeepak Kodihalli
8290b02be92SPatrick Venture } // namespace temp_readings
8300b02be92SPatrick Venture } // namespace dcmi
831ee717d71SDeepak Kodihalli
832cce9ffd9SVernon Mauery ipmi::RspType<uint8_t, // total instances for entity id
833cce9ffd9SVernon Mauery uint8_t, // number of instances in this reply
834cce9ffd9SVernon Mauery std::vector< // zero or more of the following two bytes
835cce9ffd9SVernon Mauery std::tuple<uint7_t, // temperature value
836cce9ffd9SVernon Mauery bool, // sign bit
837cce9ffd9SVernon Mauery uint8_t // entity instance
838cce9ffd9SVernon Mauery >>>
getTempReadings(ipmi::Context::ptr & ctx,uint8_t sensorType,uint8_t entityId,uint8_t entityInstance,uint8_t instanceStart)839cce9ffd9SVernon Mauery getTempReadings(ipmi::Context::ptr& ctx, uint8_t sensorType,
840cce9ffd9SVernon Mauery uint8_t entityId, uint8_t entityInstance,
841cce9ffd9SVernon Mauery uint8_t instanceStart)
842ee717d71SDeepak Kodihalli {
843cce9ffd9SVernon Mauery auto it = dcmi::entityIdToName.find(entityId);
8440b45955fSDeepak Kodihalli if (it == dcmi::entityIdToName.end())
845ee717d71SDeepak Kodihalli {
8467fa2871dSGeorge Liu lg2::error("Unknown Entity ID: {ENTITY_ID}", "ENTITY_ID", entityId);
847cce9ffd9SVernon Mauery return ipmi::responseInvalidFieldRequest();
848ee717d71SDeepak Kodihalli }
849ee717d71SDeepak Kodihalli
850cce9ffd9SVernon Mauery if (sensorType != dcmi::temperatureSensorType)
851ee717d71SDeepak Kodihalli {
8527fa2871dSGeorge Liu lg2::error("Invalid sensor type: {SENSOR_TYPE}", "SENSOR_TYPE",
8537fa2871dSGeorge Liu sensorType);
854cce9ffd9SVernon Mauery return ipmi::responseInvalidFieldRequest();
855ee717d71SDeepak Kodihalli }
856ee717d71SDeepak Kodihalli
857cce9ffd9SVernon Mauery uint8_t requestedRecords = (entityInstance == 0) ? dcmi::maxRecords : 1;
858ee717d71SDeepak Kodihalli
859cce9ffd9SVernon Mauery // Read requested instances
860cce9ffd9SVernon Mauery const auto& [temps, totalInstances] = dcmi::temp_readings::read(
861cce9ffd9SVernon Mauery ctx, it->second, instanceStart, requestedRecords);
862ee717d71SDeepak Kodihalli
863cce9ffd9SVernon Mauery auto numInstances = static_cast<uint8_t>(temps.size());
864cce9ffd9SVernon Mauery
865cce9ffd9SVernon Mauery return ipmi::responseSuccess(totalInstances, numInstances, temps);
866ee717d71SDeepak Kodihalli }
867ee717d71SDeepak Kodihalli
setDCMIConfParams(ipmi::Context::ptr & ctx,uint8_t parameter,uint8_t setSelector,ipmi::message::Payload & payload)8686475b5c9SVernon Mauery ipmi::RspType<> setDCMIConfParams(ipmi::Context::ptr& ctx, uint8_t parameter,
8696475b5c9SVernon Mauery uint8_t setSelector,
8706475b5c9SVernon Mauery ipmi::message::Payload& payload)
87122be97b3SNagaraju Goruganti {
8726475b5c9SVernon Mauery if (setSelector)
87322be97b3SNagaraju Goruganti {
8746475b5c9SVernon Mauery return ipmi::responseInvalidFieldRequest();
87522be97b3SNagaraju Goruganti }
87622be97b3SNagaraju Goruganti // Take action based on the Parameter Selector
8776475b5c9SVernon Mauery switch (static_cast<dcmi::DCMIConfigParameters>(parameter))
87822be97b3SNagaraju Goruganti {
87922be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::ActivateDHCP:
8806475b5c9SVernon Mauery {
8816475b5c9SVernon Mauery uint7_t reserved{};
8826475b5c9SVernon Mauery bool activate{};
8836475b5c9SVernon Mauery if (payload.unpack(activate, reserved) || !payload.fullyUnpacked())
8846475b5c9SVernon Mauery {
8856475b5c9SVernon Mauery return ipmi::responseReqDataLenInvalid();
8866475b5c9SVernon Mauery }
8876475b5c9SVernon Mauery if (reserved)
8886475b5c9SVernon Mauery {
8896475b5c9SVernon Mauery return ipmi::responseInvalidFieldRequest();
8906475b5c9SVernon Mauery }
8916475b5c9SVernon Mauery std::optional<EthernetInterface::DHCPConf> dhcpEnabled =
8926475b5c9SVernon Mauery dcmi::getDHCPEnabled(ctx);
8936475b5c9SVernon Mauery if (!dhcpEnabled)
8946475b5c9SVernon Mauery {
8956475b5c9SVernon Mauery return ipmi::responseUnspecifiedError();
8966475b5c9SVernon Mauery }
8976475b5c9SVernon Mauery if (activate &&
8986475b5c9SVernon Mauery (dhcpEnabled.value() != EthernetInterface::DHCPConf::none))
89922be97b3SNagaraju Goruganti {
90022be97b3SNagaraju Goruganti // When these conditions are met we have to trigger DHCP
9016475b5c9SVernon Mauery // protocol restart using the latest parameter settings,
9026475b5c9SVernon Mauery // but as per n/w manager design, each time when we
9036475b5c9SVernon Mauery // update n/w parameters, n/w service is restarted. So
9046475b5c9SVernon Mauery // we no need to take any action in this case.
90522be97b3SNagaraju Goruganti }
90622be97b3SNagaraju Goruganti break;
9076475b5c9SVernon Mauery }
90822be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DiscoveryConfig:
90922be97b3SNagaraju Goruganti {
9106475b5c9SVernon Mauery bool option12{};
9116475b5c9SVernon Mauery uint6_t reserved1{};
9126475b5c9SVernon Mauery bool randBackOff{};
9136475b5c9SVernon Mauery if (payload.unpack(option12, reserved1, randBackOff) ||
9146475b5c9SVernon Mauery !payload.fullyUnpacked())
91522be97b3SNagaraju Goruganti {
9166475b5c9SVernon Mauery return ipmi::responseReqDataLenInvalid();
91722be97b3SNagaraju Goruganti }
91822be97b3SNagaraju Goruganti // Systemd-networkd doesn't support Random Back off
9196475b5c9SVernon Mauery if (reserved1 || randBackOff)
92022be97b3SNagaraju Goruganti {
9216475b5c9SVernon Mauery return ipmi::responseInvalidFieldRequest();
92222be97b3SNagaraju Goruganti }
9236475b5c9SVernon Mauery dcmi::setDHCPOption(ctx, dcmi::dhcpOpt12Enabled, option12);
92422be97b3SNagaraju Goruganti break;
9256475b5c9SVernon Mauery }
92622be97b3SNagaraju Goruganti // Systemd-networkd doesn't allow to configure DHCP timigs
92722be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DHCPTiming1:
92822be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DHCPTiming2:
92922be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DHCPTiming3:
93022be97b3SNagaraju Goruganti default:
9316475b5c9SVernon Mauery return ipmi::responseInvalidFieldRequest();
93222be97b3SNagaraju Goruganti }
9336475b5c9SVernon Mauery return ipmi::responseSuccess();
93422be97b3SNagaraju Goruganti }
9356475b5c9SVernon Mauery
getDCMIConfParams(ipmi::Context::ptr & ctx,uint8_t parameter,uint8_t setSelector)9361318a5edSPatrick Williams ipmi::RspType<ipmi::message::Payload> getDCMIConfParams(
9371318a5edSPatrick Williams ipmi::Context::ptr& ctx, uint8_t parameter, uint8_t setSelector)
93822be97b3SNagaraju Goruganti {
9396475b5c9SVernon Mauery if (setSelector)
94022be97b3SNagaraju Goruganti {
9416475b5c9SVernon Mauery return ipmi::responseInvalidFieldRequest();
94222be97b3SNagaraju Goruganti }
9436475b5c9SVernon Mauery ipmi::message::Payload payload;
9446475b5c9SVernon Mauery payload.pack(dcmi::specMajorVersion, dcmi::specMinorVersion,
9456475b5c9SVernon Mauery dcmi::configParameterRevision);
94622be97b3SNagaraju Goruganti
94722be97b3SNagaraju Goruganti // Take action based on the Parameter Selector
9486475b5c9SVernon Mauery switch (static_cast<dcmi::DCMIConfigParameters>(parameter))
94922be97b3SNagaraju Goruganti {
95022be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::ActivateDHCP:
9516475b5c9SVernon Mauery payload.pack(dcmi::activateDhcpReply);
95222be97b3SNagaraju Goruganti break;
95322be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DiscoveryConfig:
95422be97b3SNagaraju Goruganti {
9556475b5c9SVernon Mauery uint8_t discovery{};
9566475b5c9SVernon Mauery std::optional<bool> enabled =
9576475b5c9SVernon Mauery dcmi::getDHCPOption(ctx, dcmi::dhcpOpt12Enabled);
9586475b5c9SVernon Mauery if (!enabled.has_value())
9596475b5c9SVernon Mauery {
9606475b5c9SVernon Mauery return ipmi::responseUnspecifiedError();
96122be97b3SNagaraju Goruganti }
9626475b5c9SVernon Mauery if (enabled.value())
9636475b5c9SVernon Mauery {
9646475b5c9SVernon Mauery discovery = dcmi::option12Mask;
9656475b5c9SVernon Mauery }
9666475b5c9SVernon Mauery payload.pack(discovery);
96722be97b3SNagaraju Goruganti break;
9686475b5c9SVernon Mauery }
96922be97b3SNagaraju Goruganti // Get below values from Systemd-networkd source code
97022be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DHCPTiming1:
9716475b5c9SVernon Mauery payload.pack(dcmi::dhcpTiming1);
97222be97b3SNagaraju Goruganti break;
97322be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DHCPTiming2:
9746475b5c9SVernon Mauery payload.pack(dcmi::dhcpTiming2);
97522be97b3SNagaraju Goruganti break;
97622be97b3SNagaraju Goruganti case dcmi::DCMIConfigParameters::DHCPTiming3:
9776475b5c9SVernon Mauery payload.pack(dcmi::dhcpTiming3);
97822be97b3SNagaraju Goruganti break;
97922be97b3SNagaraju Goruganti default:
9806475b5c9SVernon Mauery return ipmi::responseInvalidFieldRequest();
98122be97b3SNagaraju Goruganti }
98222be97b3SNagaraju Goruganti
983af762de5SThang Tran return ipmi::responseSuccess(payload);
98422be97b3SNagaraju Goruganti }
98522be97b3SNagaraju Goruganti
readPower(ipmi::Context::ptr & ctx)986056fab1aSVernon Mauery static std::optional<uint16_t> readPower(ipmi::Context::ptr& ctx)
98766c5fda2SMarri Devender Rao {
988056fab1aSVernon Mauery std::ifstream sensorFile(POWER_READING_SENSOR);
989056fab1aSVernon Mauery std::string objectPath;
990056fab1aSVernon Mauery if (!sensorFile.is_open())
991056fab1aSVernon Mauery {
9927fa2871dSGeorge Liu lg2::error(
9937fa2871dSGeorge Liu "Power reading configuration file not found: {POWER_SENSOR_FILE}",
9947fa2871dSGeorge Liu "POWER_SENSOR_FILE", std::string_view{POWER_READING_SENSOR});
995056fab1aSVernon Mauery return std::nullopt;
996056fab1aSVernon Mauery }
997056fab1aSVernon Mauery
998056fab1aSVernon Mauery auto data = nlohmann::json::parse(sensorFile, nullptr, false);
999056fab1aSVernon Mauery if (data.is_discarded())
1000056fab1aSVernon Mauery {
10017fa2871dSGeorge Liu lg2::error("Error in parsing configuration file: {POWER_SENSOR_FILE}",
10027fa2871dSGeorge Liu "POWER_SENSOR_FILE", std::string_view{POWER_READING_SENSOR});
1003056fab1aSVernon Mauery return std::nullopt;
1004056fab1aSVernon Mauery }
1005056fab1aSVernon Mauery
1006056fab1aSVernon Mauery objectPath = data.value("path", "");
1007056fab1aSVernon Mauery if (objectPath.empty())
1008056fab1aSVernon Mauery {
10097fa2871dSGeorge Liu lg2::error(
10107fa2871dSGeorge Liu "Power sensor D-Bus object path is empty: {POWER_SENSOR_FILE}",
10117fa2871dSGeorge Liu "POWER_SENSOR_FILE", std::string_view{POWER_READING_SENSOR});
1012056fab1aSVernon Mauery return std::nullopt;
1013056fab1aSVernon Mauery }
1014056fab1aSVernon Mauery
1015056fab1aSVernon Mauery // Return default value if failed to read from D-Bus object
1016056fab1aSVernon Mauery std::string service{};
10171318a5edSPatrick Williams boost::system::error_code ec =
10181318a5edSPatrick Williams ipmi::getService(ctx, dcmi::sensorValueIntf, objectPath, service);
1019056fab1aSVernon Mauery if (ec.value())
1020056fab1aSVernon Mauery {
10217fa2871dSGeorge Liu lg2::error("Failed to fetch service for D-Bus object, "
10227fa2871dSGeorge Liu "object path: {OBJECT_PATH}, interface: {INTERFACE}",
10237fa2871dSGeorge Liu "OBJECT_PATH", objectPath, "INTERFACE",
10247fa2871dSGeorge Liu dcmi::sensorValueIntf);
1025056fab1aSVernon Mauery return std::nullopt;
1026056fab1aSVernon Mauery }
1027056fab1aSVernon Mauery
1028056fab1aSVernon Mauery // Read the sensor value and scale properties
1029056fab1aSVernon Mauery double value{};
1030056fab1aSVernon Mauery ec = ipmi::getDbusProperty(ctx, service, objectPath, dcmi::sensorValueIntf,
1031056fab1aSVernon Mauery dcmi::sensorValueProp, value);
1032056fab1aSVernon Mauery if (ec.value())
1033056fab1aSVernon Mauery {
10347fa2871dSGeorge Liu lg2::error("Failed to read power value from D-Bus object, "
10357fa2871dSGeorge Liu "object path: {OBJECT_PATH}, interface: {INTERFACE}",
10367fa2871dSGeorge Liu "OBJECT_PATH", objectPath, "INTERFACE",
10377fa2871dSGeorge Liu dcmi::sensorValueIntf);
1038056fab1aSVernon Mauery return std::nullopt;
1039056fab1aSVernon Mauery }
1040056fab1aSVernon Mauery auto power = static_cast<uint16_t>(value);
1041056fab1aSVernon Mauery return power;
1042056fab1aSVernon Mauery }
1043056fab1aSVernon Mauery
1044056fab1aSVernon Mauery ipmi::RspType<uint16_t, // current power
1045056fab1aSVernon Mauery uint16_t, // minimum power
1046056fab1aSVernon Mauery uint16_t, // maximum power
1047056fab1aSVernon Mauery uint16_t, // average power
1048056fab1aSVernon Mauery uint32_t, // timestamp
1049056fab1aSVernon Mauery uint32_t, // sample period ms
1050056fab1aSVernon Mauery uint6_t, // reserved
1051056fab1aSVernon Mauery bool, // power measurement active
1052056fab1aSVernon Mauery bool // reserved
1053056fab1aSVernon Mauery >
getPowerReading(ipmi::Context::ptr & ctx,uint8_t mode,uint8_t attributes,uint8_t reserved)1054056fab1aSVernon Mauery getPowerReading(ipmi::Context::ptr& ctx, uint8_t mode, uint8_t attributes,
1055056fab1aSVernon Mauery uint8_t reserved)
1056056fab1aSVernon Mauery {
10572c2af2caSKirill Pakhomov if (!dcmi::isDCMIPowerMgmtSupported())
10582c2af2caSKirill Pakhomov {
10597fa2871dSGeorge Liu lg2::error("DCMI Power management is unsupported!");
1060056fab1aSVernon Mauery return ipmi::responseInvalidCommand();
1061056fab1aSVernon Mauery }
1062056fab1aSVernon Mauery if (reserved)
1063056fab1aSVernon Mauery {
1064056fab1aSVernon Mauery return ipmi::responseInvalidFieldRequest();
10652c2af2caSKirill Pakhomov }
10662c2af2caSKirill Pakhomov
1067056fab1aSVernon Mauery enum class PowerMode : uint8_t
1068056fab1aSVernon Mauery {
1069056fab1aSVernon Mauery SystemPowerStatistics = 1,
1070056fab1aSVernon Mauery EnhancedSystemPowerStatistics = 2,
1071056fab1aSVernon Mauery };
10729c966e01SMarri Devender Rao
1073056fab1aSVernon Mauery if (static_cast<PowerMode>(mode) != PowerMode::SystemPowerStatistics)
107466c5fda2SMarri Devender Rao {
1075056fab1aSVernon Mauery return ipmi::responseInvalidFieldRequest();
107666c5fda2SMarri Devender Rao }
1077056fab1aSVernon Mauery if (attributes)
107866c5fda2SMarri Devender Rao {
1079056fab1aSVernon Mauery return ipmi::responseInvalidFieldRequest();
108066c5fda2SMarri Devender Rao }
10819c966e01SMarri Devender Rao
1082056fab1aSVernon Mauery std::optional<uint16_t> powerResp = readPower(ctx);
1083056fab1aSVernon Mauery if (!powerResp)
1084056fab1aSVernon Mauery {
1085056fab1aSVernon Mauery return ipmi::responseUnspecifiedError();
1086056fab1aSVernon Mauery }
1087056fab1aSVernon Mauery auto& power = powerResp.value();
1088056fab1aSVernon Mauery
10899c966e01SMarri Devender Rao // TODO: openbmc/openbmc#2819
10908466b792SGunnar Mills // Minimum, Maximum, Average power, TimeFrame, TimeStamp,
10919c966e01SMarri Devender Rao // PowerReadingState readings need to be populated
10929c966e01SMarri Devender Rao // after Telemetry changes.
1093056fab1aSVernon Mauery constexpr uint32_t samplePeriod = 1;
1094056fab1aSVernon Mauery constexpr uint6_t reserved1 = 0;
1095056fab1aSVernon Mauery constexpr bool measurementActive = true;
1096056fab1aSVernon Mauery constexpr bool reserved2 = false;
1097056fab1aSVernon Mauery auto timestamp = static_cast<uint32_t>(time(nullptr));
1098056fab1aSVernon Mauery return ipmi::responseSuccess(power, power, power, power, timestamp,
1099056fab1aSVernon Mauery samplePeriod, reserved1, measurementActive,
1100056fab1aSVernon Mauery reserved2);
110166c5fda2SMarri Devender Rao }
110266c5fda2SMarri Devender Rao
11030b45955fSDeepak Kodihalli namespace dcmi
11040b45955fSDeepak Kodihalli {
11050b45955fSDeepak Kodihalli namespace sensor_info
11060b45955fSDeepak Kodihalli {
11070b45955fSDeepak Kodihalli
read(const std::string & type,uint8_t instance,const nlohmann::json & config,uint8_t count)1108*69b4c281SPatrick Williams std::tuple<std::vector<uint16_t>, uint8_t> read(
1109*69b4c281SPatrick Williams const std::string& type, uint8_t instance, const nlohmann::json& config,
1110*69b4c281SPatrick Williams uint8_t count)
1111dd4cff13SDeepak Kodihalli {
111253d0cf1dSVernon Mauery std::vector<uint16_t> responses{};
1113dd4cff13SDeepak Kodihalli
111453d0cf1dSVernon Mauery static const std::vector<nlohmann::json> empty{};
111553d0cf1dSVernon Mauery std::vector<nlohmann::json> readings = config.value(type, empty);
111653d0cf1dSVernon Mauery uint8_t totalInstances = std::min(readings.size(), maxInstances);
1117dd4cff13SDeepak Kodihalli for (const auto& reading : readings)
1118dd4cff13SDeepak Kodihalli {
111953d0cf1dSVernon Mauery // limit to requested count
112053d0cf1dSVernon Mauery if (responses.size() == count)
1121dd4cff13SDeepak Kodihalli {
1122dd4cff13SDeepak Kodihalli break;
1123dd4cff13SDeepak Kodihalli }
1124dd4cff13SDeepak Kodihalli
1125dd4cff13SDeepak Kodihalli uint8_t instanceNum = reading.value("instance", 0);
1126dd4cff13SDeepak Kodihalli // Not in the instance range we're interested in
112753d0cf1dSVernon Mauery if (instanceNum < instance)
1128dd4cff13SDeepak Kodihalli {
1129dd4cff13SDeepak Kodihalli continue;
1130dd4cff13SDeepak Kodihalli }
1131dd4cff13SDeepak Kodihalli
11325ea83fadSThang Tran uint16_t recordId = reading.value("record_id", 0);
113353d0cf1dSVernon Mauery responses.emplace_back(recordId);
1134dd4cff13SDeepak Kodihalli }
1135dd4cff13SDeepak Kodihalli
113653d0cf1dSVernon Mauery return std::make_tuple(responses, totalInstances);
11370b45955fSDeepak Kodihalli }
11380b45955fSDeepak Kodihalli
11390b45955fSDeepak Kodihalli } // namespace sensor_info
11400b45955fSDeepak Kodihalli } // namespace dcmi
11410b45955fSDeepak Kodihalli
114253d0cf1dSVernon Mauery ipmi::RspType<uint8_t, // total available instances
114353d0cf1dSVernon Mauery uint8_t, // number of records in this response
114453d0cf1dSVernon Mauery std::vector<uint16_t> // records
114553d0cf1dSVernon Mauery >
getSensorInfo(uint8_t sensorType,uint8_t entityId,uint8_t entityInstance,uint8_t instanceStart)114653d0cf1dSVernon Mauery getSensorInfo(uint8_t sensorType, uint8_t entityId, uint8_t entityInstance,
114753d0cf1dSVernon Mauery uint8_t instanceStart)
11480b45955fSDeepak Kodihalli {
114953d0cf1dSVernon Mauery auto it = dcmi::entityIdToName.find(entityId);
11500b45955fSDeepak Kodihalli if (it == dcmi::entityIdToName.end())
11510b45955fSDeepak Kodihalli {
11527fa2871dSGeorge Liu lg2::error("Unknown Entity ID: {ENTITY_ID}", "ENTITY_ID", entityId);
115353d0cf1dSVernon Mauery return ipmi::responseInvalidFieldRequest();
11540b45955fSDeepak Kodihalli }
11550b45955fSDeepak Kodihalli
115653d0cf1dSVernon Mauery if (sensorType != dcmi::temperatureSensorType)
11570b45955fSDeepak Kodihalli {
11587fa2871dSGeorge Liu lg2::error("Invalid sensor type: {SENSOR_TYPE}", "SENSOR_TYPE",
11597fa2871dSGeorge Liu sensorType);
116053d0cf1dSVernon Mauery return ipmi::responseInvalidFieldRequest();
11610b45955fSDeepak Kodihalli }
11620b45955fSDeepak Kodihalli
116353d0cf1dSVernon Mauery nlohmann::json config = dcmi::parseJSONConfig(dcmi::gDCMISensorsConfig);
11640b45955fSDeepak Kodihalli
116553d0cf1dSVernon Mauery uint8_t requestedRecords = (entityInstance == 0) ? dcmi::maxRecords : 1;
116653d0cf1dSVernon Mauery // Read requested instances
116753d0cf1dSVernon Mauery const auto& [sensors, totalInstances] = dcmi::sensor_info::read(
116853d0cf1dSVernon Mauery it->second, instanceStart, config, requestedRecords);
116953d0cf1dSVernon Mauery uint8_t numRecords = sensors.size();
11700b45955fSDeepak Kodihalli
117153d0cf1dSVernon Mauery return ipmi::responseSuccess(totalInstances, numRecords, sensors);
11720b45955fSDeepak Kodihalli }
11730b45955fSDeepak Kodihalli
registerNetFnDcmiFunctions()11745087b075SGeorge Liu void registerNetFnDcmiFunctions()
117598a23840SMatthew Barth {
11760573237fSTom // <Get Power Limit>
1177d4222fd3SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1178d4222fd3SVernon Mauery ipmi::dcmi::cmdGetPowerLimit, ipmi::Privilege::User,
1179d4222fd3SVernon Mauery getPowerLimit);
11806f6dd4d7STom Joseph
118146fa37d9STom Joseph // <Set Power Limit>
1182d4222fd3SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1183d4222fd3SVernon Mauery ipmi::dcmi::cmdSetPowerLimit,
1184d4222fd3SVernon Mauery ipmi::Privilege::Operator, setPowerLimit);
118546fa37d9STom Joseph
11866c8d51baSTom Joseph // <Activate/Deactivate Power Limit>
1187d4222fd3SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1188d4222fd3SVernon Mauery ipmi::dcmi::cmdActDeactivatePwrLimit,
1189d4222fd3SVernon Mauery ipmi::Privilege::Operator, applyPowerLimit);
11906c8d51baSTom Joseph
11916f6dd4d7STom Joseph // <Get Asset Tag>
1192dca4720fSVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1193dca4720fSVernon Mauery ipmi::dcmi::cmdGetAssetTag, ipmi::Privilege::User,
1194dca4720fSVernon Mauery getAssetTag);
1195545dd232STom Joseph
1196545dd232STom Joseph // <Set Asset Tag>
1197dca4720fSVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1198dca4720fSVernon Mauery ipmi::dcmi::cmdSetAssetTag, ipmi::Privilege::Operator,
1199dca4720fSVernon Mauery setAssetTag);
12008f7a6f68SVladislav Vovchenko
12018991dd62SGunnar Mills // <Get Management Controller Identifier String>
1202efb5ae55SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1203efb5ae55SVernon Mauery ipmi::dcmi::cmdGetMgmtCntlrIdString,
1204efb5ae55SVernon Mauery ipmi::Privilege::User, getMgmntCtrlIdStr);
12058f7a6f68SVladislav Vovchenko
12068f7a6f68SVladislav Vovchenko // <Set Management Controller Identifier String>
1207efb5ae55SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1208efb5ae55SVernon Mauery ipmi::dcmi::cmdSetMgmtCntlrIdString,
1209efb5ae55SVernon Mauery ipmi::Privilege::Admin, setMgmntCtrlIdStr);
12108f7a6f68SVladislav Vovchenko
1211e29be41fSDhruvaraj Subhashchandran // <Get DCMI capabilities>
1212f038dc09SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1213f038dc09SVernon Mauery ipmi::dcmi::cmdGetDcmiCapabilitiesInfo,
1214f038dc09SVernon Mauery ipmi::Privilege::User, getDCMICapabilities);
1215ee717d71SDeepak Kodihalli
121666c5fda2SMarri Devender Rao // <Get Power Reading>
1217056fab1aSVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
1218056fab1aSVernon Mauery ipmi::dcmi::cmdGetPowerReading, ipmi::Privilege::User,
1219056fab1aSVernon Mauery getPowerReading);
1220056fab1aSVernon Mauery
1221042e9db4Sadarshgrami // The Get sensor should get the senor details dynamically when
1222042e9db4Sadarshgrami // FEATURE_DYNAMIC_SENSORS is enabled.
1223042e9db4Sadarshgrami #ifndef FEATURE_DYNAMIC_SENSORS
12240b45955fSDeepak Kodihalli // <Get Sensor Info>
122553d0cf1dSVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
122653d0cf1dSVernon Mauery ipmi::dcmi::cmdGetDcmiSensorInfo,
122753d0cf1dSVernon Mauery ipmi::Privilege::Operator, getSensorInfo);
12283dad826bSThang Tran
12293dad826bSThang Tran // <Get Temperature Readings>
12303dad826bSThang Tran registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
12313dad826bSThang Tran ipmi::dcmi::cmdGetTemperatureReadings,
12323dad826bSThang Tran ipmi::Privilege::User, getTempReadings);
1233042e9db4Sadarshgrami #endif
123422be97b3SNagaraju Goruganti // <Get DCMI Configuration Parameters>
12356475b5c9SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
12366475b5c9SVernon Mauery ipmi::dcmi::cmdGetDcmiConfigParameters,
12376475b5c9SVernon Mauery ipmi::Privilege::User, getDCMIConfParams);
123822be97b3SNagaraju Goruganti
123922be97b3SNagaraju Goruganti // <Set DCMI Configuration Parameters>
12406475b5c9SVernon Mauery registerGroupHandler(ipmi::prioOpenBmcBase, ipmi::groupDCMI,
12416475b5c9SVernon Mauery ipmi::dcmi::cmdSetDcmiConfigParameters,
12426475b5c9SVernon Mauery ipmi::Privilege::Admin, setDCMIConfParams);
124322be97b3SNagaraju Goruganti
124498a23840SMatthew Barth return;
124598a23840SMatthew Barth }
1246