1a835eaa0SJia, Chunhui /*
2a835eaa0SJia, Chunhui // Copyright (c) 2018 Intel Corporation
3a835eaa0SJia, Chunhui //
4a835eaa0SJia, Chunhui // Licensed under the Apache License, Version 2.0 (the "License");
5a835eaa0SJia, Chunhui // you may not use this file except in compliance with the License.
6a835eaa0SJia, Chunhui // You may obtain a copy of the License at
7a835eaa0SJia, Chunhui //
8a835eaa0SJia, Chunhui //      http://www.apache.org/licenses/LICENSE-2.0
9a835eaa0SJia, Chunhui //
10a835eaa0SJia, Chunhui // Unless required by applicable law or agreed to in writing, software
11a835eaa0SJia, Chunhui // distributed under the License is distributed on an "AS IS" BASIS,
12a835eaa0SJia, Chunhui // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a835eaa0SJia, Chunhui // See the License for the specific language governing permissions and
14a835eaa0SJia, Chunhui // limitations under the License.
15a835eaa0SJia, Chunhui */
16a835eaa0SJia, Chunhui 
17c2a07d4bSPatrick Venture #include "types.hpp"
1864796041SJason M. Bills #include "xyz/openbmc_project/Common/error.hpp"
1945f04988SKuiying Wang #include "xyz/openbmc_project/Led/Physical/server.hpp"
2064796041SJason M. Bills 
219420416aSJayaprakash Mutyala #include <openssl/crypto.h>
22cc49b54bSJia, Chunhui #include <systemd/sd-journal.h>
23a835eaa0SJia, Chunhui 
247a04f3a4SChen Yugang #include <appcommands.hpp>
2591244a6aSJames Feist #include <boost/container/flat_map.hpp>
2623737fe3SYong Li #include <boost/process/child.hpp>
2723737fe3SYong Li #include <boost/process/io.hpp>
280669d193SYong Li #include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
2964796041SJason M. Bills #include <commandutils.hpp>
30ce4e73fdSZhikui Ren #include <gpiod.hpp>
31cc49b54bSJia, Chunhui #include <ipmid/api.hpp>
325480ef62SVernon Mauery #include <ipmid/utils.hpp>
3363efafacSJames Feist #include <nlohmann/json.hpp>
34a835eaa0SJia, Chunhui #include <oemcommands.hpp>
35a835eaa0SJia, Chunhui #include <phosphor-logging/log.hpp>
36a835eaa0SJia, Chunhui #include <sdbusplus/bus.hpp>
37d509eb91SSuryakanth Sekar #include <sdbusplus/message/types.hpp>
3897cf96e6SChen Yugang #include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
394f7e76bbSChen,Yugang #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
404f7e76bbSChen,Yugang #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
41773703a5SCheng C Yang #include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
42d801e463SRichard Marian Thomaiyar #include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
438d4f8d73SRichard Marian Thomaiyar #include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
44a835eaa0SJia, Chunhui 
45fcd2d3a9SJames Feist #include <array>
46fcd2d3a9SJames Feist #include <filesystem>
47fcd2d3a9SJames Feist #include <iostream>
48fcd2d3a9SJames Feist #include <regex>
49fcd2d3a9SJames Feist #include <string>
50fcd2d3a9SJames Feist #include <variant>
51fcd2d3a9SJames Feist #include <vector>
52fcd2d3a9SJames Feist 
53a835eaa0SJia, Chunhui namespace ipmi
54a835eaa0SJia, Chunhui {
5564796041SJason M. Bills static void registerOEMFunctions() __attribute__((constructor));
564ac799d7SVernon Mauery 
5764796041SJason M. Bills static constexpr size_t maxFRUStringLength = 0x3F;
58a835eaa0SJia, Chunhui 
59d509eb91SSuryakanth Sekar static constexpr auto ethernetIntf =
60d509eb91SSuryakanth Sekar     "xyz.openbmc_project.Network.EthernetInterface";
61d509eb91SSuryakanth Sekar static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
62d509eb91SSuryakanth Sekar static constexpr auto networkService = "xyz.openbmc_project.Network";
63d509eb91SSuryakanth Sekar static constexpr auto networkRoot = "/xyz/openbmc_project/network";
64d509eb91SSuryakanth Sekar 
6597cf96e6SChen Yugang static constexpr const char* oemNmiSourceIntf =
6697cf96e6SChen Yugang     "xyz.openbmc_project.Chassis.Control.NMISource";
6739736d59SChen Yugang static constexpr const char* oemNmiSourceObjPath =
6897cf96e6SChen Yugang     "/xyz/openbmc_project/Chassis/Control/NMISource";
6939736d59SChen Yugang static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
7039736d59SChen Yugang static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
7139736d59SChen Yugang 
7263efafacSJames Feist static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
732030d7c8Ssrikanta mondal static constexpr const char* multiNodeObjPath =
742030d7c8Ssrikanta mondal     "/xyz/openbmc_project/MultiNode/Status";
752030d7c8Ssrikanta mondal static constexpr const char* multiNodeIntf =
762030d7c8Ssrikanta mondal     "xyz.openbmc_project.Chassis.MultiNode";
7763efafacSJames Feist 
7839736d59SChen Yugang enum class NmiSource : uint8_t
7939736d59SChen Yugang {
8039736d59SChen Yugang     none = 0,
8197cf96e6SChen Yugang     frontPanelButton = 1,
8297cf96e6SChen Yugang     watchdog = 2,
8397cf96e6SChen Yugang     chassisCmd = 3,
8497cf96e6SChen Yugang     memoryError = 4,
8597cf96e6SChen Yugang     pciBusError = 5,
8697cf96e6SChen Yugang     pch = 6,
8797cf96e6SChen Yugang     chipset = 7,
8839736d59SChen Yugang };
8939736d59SChen Yugang 
90822b0b40SSuryakanth Sekar enum class SpecialUserIndex : uint8_t
91822b0b40SSuryakanth Sekar {
92822b0b40SSuryakanth Sekar     rootUser = 0,
93822b0b40SSuryakanth Sekar     atScaleDebugUser = 1
94822b0b40SSuryakanth Sekar };
95822b0b40SSuryakanth Sekar 
96d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeService =
97d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.RestrictionMode.Manager";
98d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeBasePath =
99d801e463SRichard Marian Thomaiyar     "/xyz/openbmc_project/control/security/restriction_mode";
100d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeIntf =
101d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.Control.Security.RestrictionMode";
102d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeProperty = "RestrictionMode";
103d801e463SRichard Marian Thomaiyar 
104d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeService =
105d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.SpecialMode";
106d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeBasePath =
107a7b74288SRichard Marian Thomaiyar     "/xyz/openbmc_project/security/special_mode";
108d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeIntf =
109d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.Security.SpecialMode";
110d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeProperty = "SpecialMode";
111d801e463SRichard Marian Thomaiyar 
112d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertyIntf =
113d801e463SRichard Marian Thomaiyar     "org.freedesktop.DBus.Properties";
114d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertyGetMethod = "Get";
115d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertySetMethod = "Set";
116d801e463SRichard Marian Thomaiyar 
117a835eaa0SJia, Chunhui // return code: 0 successful
118a835eaa0SJia, Chunhui int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
119a835eaa0SJia, Chunhui {
120a835eaa0SJia, Chunhui     std::string objpath = "/xyz/openbmc_project/FruDevice";
121a835eaa0SJia, Chunhui     std::string intf = "xyz.openbmc_project.FruDeviceManager";
122a835eaa0SJia, Chunhui     std::string service = getService(bus, intf, objpath);
123a835eaa0SJia, Chunhui     ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
124a835eaa0SJia, Chunhui     if (valueTree.empty())
125a835eaa0SJia, Chunhui     {
126a835eaa0SJia, Chunhui         phosphor::logging::log<phosphor::logging::level::ERR>(
127a835eaa0SJia, Chunhui             "No object implements interface",
128a835eaa0SJia, Chunhui             phosphor::logging::entry("INTF=%s", intf.c_str()));
129a835eaa0SJia, Chunhui         return -1;
130a835eaa0SJia, Chunhui     }
131a835eaa0SJia, Chunhui 
13264796041SJason M. Bills     for (const auto& item : valueTree)
133a835eaa0SJia, Chunhui     {
134a835eaa0SJia, Chunhui         auto interface = item.second.find("xyz.openbmc_project.FruDevice");
135a835eaa0SJia, Chunhui         if (interface == item.second.end())
136a835eaa0SJia, Chunhui         {
137a835eaa0SJia, Chunhui             continue;
138a835eaa0SJia, Chunhui         }
139a835eaa0SJia, Chunhui 
140a835eaa0SJia, Chunhui         auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
141a835eaa0SJia, Chunhui         if (property == interface->second.end())
142a835eaa0SJia, Chunhui         {
143a835eaa0SJia, Chunhui             continue;
144a835eaa0SJia, Chunhui         }
145a835eaa0SJia, Chunhui 
146a835eaa0SJia, Chunhui         try
147a835eaa0SJia, Chunhui         {
148a835eaa0SJia, Chunhui             Value variant = property->second;
1498166c8d7SVernon Mauery             std::string& result = std::get<std::string>(variant);
15064796041SJason M. Bills             if (result.size() > maxFRUStringLength)
151a835eaa0SJia, Chunhui             {
152a835eaa0SJia, Chunhui                 phosphor::logging::log<phosphor::logging::level::ERR>(
153a835eaa0SJia, Chunhui                     "FRU serial number exceed maximum length");
154a835eaa0SJia, Chunhui                 return -1;
155a835eaa0SJia, Chunhui             }
156a835eaa0SJia, Chunhui             serial = result;
157a835eaa0SJia, Chunhui             return 0;
158a835eaa0SJia, Chunhui         }
1598166c8d7SVernon Mauery         catch (std::bad_variant_access& e)
160a835eaa0SJia, Chunhui         {
16164796041SJason M. Bills             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
162a835eaa0SJia, Chunhui             return -1;
163a835eaa0SJia, Chunhui         }
164a835eaa0SJia, Chunhui     }
165a835eaa0SJia, Chunhui     return -1;
166a835eaa0SJia, Chunhui }
16764796041SJason M. Bills 
168a835eaa0SJia, Chunhui // Returns the Chassis Identifier (serial #)
169a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
170a835eaa0SJia, Chunhui                                        ipmi_request_t request,
171a835eaa0SJia, Chunhui                                        ipmi_response_t response,
17264796041SJason M. Bills                                        ipmi_data_len_t dataLen,
173a835eaa0SJia, Chunhui                                        ipmi_context_t context)
174a835eaa0SJia, Chunhui {
175a835eaa0SJia, Chunhui     std::string serial;
17664796041SJason M. Bills     if (*dataLen != 0) // invalid request if there are extra parameters
177a835eaa0SJia, Chunhui     {
17864796041SJason M. Bills         *dataLen = 0;
179a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
180a835eaa0SJia, Chunhui     }
18115419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
18215419dd5SVernon Mauery     if (getChassisSerialNumber(*dbus, serial) == 0)
183a835eaa0SJia, Chunhui     {
18464796041SJason M. Bills         *dataLen = serial.size(); // length will never exceed response length
185a835eaa0SJia, Chunhui                                   // as it is checked in getChassisSerialNumber
186a835eaa0SJia, Chunhui         char* resp = static_cast<char*>(response);
18764796041SJason M. Bills         serial.copy(resp, *dataLen);
188a835eaa0SJia, Chunhui         return IPMI_CC_OK;
189a835eaa0SJia, Chunhui     }
19064796041SJason M. Bills     *dataLen = 0;
191a835eaa0SJia, Chunhui     return IPMI_CC_RESPONSE_ERROR;
192a835eaa0SJia, Chunhui }
193a835eaa0SJia, Chunhui 
194a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195a835eaa0SJia, Chunhui                                 ipmi_request_t request,
196a835eaa0SJia, Chunhui                                 ipmi_response_t response,
19764796041SJason M. Bills                                 ipmi_data_len_t dataLen, ipmi_context_t context)
198a835eaa0SJia, Chunhui {
199a835eaa0SJia, Chunhui     static constexpr size_t safeBufferLength = 50;
200a835eaa0SJia, Chunhui     char buf[safeBufferLength] = {0};
201a835eaa0SJia, Chunhui     GUIDData* Data = reinterpret_cast<GUIDData*>(request);
202a835eaa0SJia, Chunhui 
20364796041SJason M. Bills     if (*dataLen != sizeof(GUIDData)) // 16bytes
204a835eaa0SJia, Chunhui     {
20564796041SJason M. Bills         *dataLen = 0;
206a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
207a835eaa0SJia, Chunhui     }
208a835eaa0SJia, Chunhui 
20964796041SJason M. Bills     *dataLen = 0;
210a835eaa0SJia, Chunhui 
211a835eaa0SJia, Chunhui     snprintf(
212a835eaa0SJia, Chunhui         buf, safeBufferLength,
213a835eaa0SJia, Chunhui         "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
214a835eaa0SJia, Chunhui         Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
215a835eaa0SJia, Chunhui         Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
216a835eaa0SJia, Chunhui         Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
217a835eaa0SJia, Chunhui         Data->node3, Data->node2, Data->node1);
218a835eaa0SJia, Chunhui     // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
219a835eaa0SJia, Chunhui     std::string guid = buf;
220a835eaa0SJia, Chunhui 
221a835eaa0SJia, Chunhui     std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
222a835eaa0SJia, Chunhui     std::string intf = "xyz.openbmc_project.Common.UUID";
22315419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
22415419dd5SVernon Mauery     std::string service = getService(*dbus, intf, objpath);
22515419dd5SVernon Mauery     setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
226a835eaa0SJia, Chunhui     return IPMI_CC_OK;
227a835eaa0SJia, Chunhui }
228a835eaa0SJia, Chunhui 
229b02bf095SJason M. Bills ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
230b02bf095SJason M. Bills                                              uint7_t reserved1)
231b02bf095SJason M. Bills {
232b02bf095SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
233b02bf095SJason M. Bills 
234b02bf095SJason M. Bills     try
235b02bf095SJason M. Bills     {
236b02bf095SJason M. Bills         auto service =
237b02bf095SJason M. Bills             ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
238b02bf095SJason M. Bills         ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
239b02bf095SJason M. Bills                               bmcResetDisablesIntf, "ResetOnSMI",
240b02bf095SJason M. Bills                               !disableResetOnSMI);
241b02bf095SJason M. Bills     }
242b02bf095SJason M. Bills     catch (std::exception& e)
243b02bf095SJason M. Bills     {
244b02bf095SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
245b02bf095SJason M. Bills             "Failed to set BMC reset disables",
246b02bf095SJason M. Bills             phosphor::logging::entry("EXCEPTION=%s", e.what()));
247b02bf095SJason M. Bills         return ipmi::responseUnspecifiedError();
248b02bf095SJason M. Bills     }
249b02bf095SJason M. Bills 
250b02bf095SJason M. Bills     return ipmi::responseSuccess();
251b02bf095SJason M. Bills }
252b02bf095SJason M. Bills 
253b02bf095SJason M. Bills ipmi::RspType<bool,   // disableResetOnSMI
254b02bf095SJason M. Bills               uint7_t // reserved
255b02bf095SJason M. Bills               >
256b02bf095SJason M. Bills     ipmiOEMGetBMCResetDisables()
257b02bf095SJason M. Bills {
258b02bf095SJason M. Bills     bool disableResetOnSMI = true;
259b02bf095SJason M. Bills 
260b02bf095SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
261b02bf095SJason M. Bills     try
262b02bf095SJason M. Bills     {
263b02bf095SJason M. Bills         auto service =
264b02bf095SJason M. Bills             ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
265b02bf095SJason M. Bills         Value variant =
266b02bf095SJason M. Bills             ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
267b02bf095SJason M. Bills                                   bmcResetDisablesIntf, "ResetOnSMI");
268b02bf095SJason M. Bills         disableResetOnSMI = !std::get<bool>(variant);
269b02bf095SJason M. Bills     }
270b02bf095SJason M. Bills     catch (std::exception& e)
271b02bf095SJason M. Bills     {
272b02bf095SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
273b02bf095SJason M. Bills             "Failed to get BMC reset disables",
274b02bf095SJason M. Bills             phosphor::logging::entry("EXCEPTION=%s", e.what()));
275b02bf095SJason M. Bills         return ipmi::responseUnspecifiedError();
276b02bf095SJason M. Bills     }
277b02bf095SJason M. Bills 
278b02bf095SJason M. Bills     return ipmi::responseSuccess(disableResetOnSMI, 0);
279b02bf095SJason M. Bills }
280b02bf095SJason M. Bills 
281a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
282a835eaa0SJia, Chunhui                             ipmi_request_t request, ipmi_response_t response,
283a835eaa0SJia, Chunhui                             ipmi_data_len_t dataLen, ipmi_context_t context)
284a835eaa0SJia, Chunhui {
285a835eaa0SJia, Chunhui     DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
286a835eaa0SJia, Chunhui 
28764796041SJason M. Bills     if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
288a835eaa0SJia, Chunhui     {
289a835eaa0SJia, Chunhui         *dataLen = 0;
290a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
291a835eaa0SJia, Chunhui     }
29264796041SJason M. Bills     std::string idString((char*)data->biosId, data->biosIDLength);
293*fb9f1aa1SChalapathi Venkataramashetty     for (auto idChar : idString)
294*fb9f1aa1SChalapathi Venkataramashetty     {
295*fb9f1aa1SChalapathi Venkataramashetty         if (!std::isprint(static_cast<unsigned char>(idChar)))
296*fb9f1aa1SChalapathi Venkataramashetty         {
297*fb9f1aa1SChalapathi Venkataramashetty             phosphor::logging::log<phosphor::logging::level::ERR>(
298*fb9f1aa1SChalapathi Venkataramashetty                 "BIOS ID contains non printable character");
299*fb9f1aa1SChalapathi Venkataramashetty             return IPMI_CC_INVALID_FIELD_REQUEST;
300*fb9f1aa1SChalapathi Venkataramashetty         }
301*fb9f1aa1SChalapathi Venkataramashetty     }
302a835eaa0SJia, Chunhui 
30315419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
304899bfd15SChalapathi     std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
305899bfd15SChalapathi     setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
3062742b85cSYong Li                     biosVersionProp, idString);
307a835eaa0SJia, Chunhui     uint8_t* bytesWritten = static_cast<uint8_t*>(response);
308a835eaa0SJia, Chunhui     *bytesWritten =
30964796041SJason M. Bills         data->biosIDLength; // how many bytes are written into storage
310a835eaa0SJia, Chunhui     *dataLen = 1;
311a835eaa0SJia, Chunhui     return IPMI_CC_OK;
312a835eaa0SJia, Chunhui }
313a835eaa0SJia, Chunhui 
314e99e7ed3SAppaRao Puli bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
315e99e7ed3SAppaRao Puli                   uint8_t& meMajor, uint8_t& meMinor)
316a835eaa0SJia, Chunhui {
3177a04f3a4SChen Yugang     // step 1 : get BMC Major and Minor numbers from its DBUS property
318e99e7ed3SAppaRao Puli     std::string bmcVersion;
319e99e7ed3SAppaRao Puli     if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
3207a04f3a4SChen Yugang     {
3217a04f3a4SChen Yugang         return false;
322a835eaa0SJia, Chunhui     }
323a835eaa0SJia, Chunhui 
324e99e7ed3SAppaRao Puli     std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
3257a04f3a4SChen Yugang     if (rev.has_value())
326a835eaa0SJia, Chunhui     {
3277a04f3a4SChen Yugang         MetaRevision revision = rev.value();
3287a04f3a4SChen Yugang         bmcMajor = revision.major;
3297a04f3a4SChen Yugang 
3307a04f3a4SChen Yugang         revision.minor = (revision.minor > 99 ? 99 : revision.minor);
3317a04f3a4SChen Yugang         bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
3327a04f3a4SChen Yugang     }
3337a04f3a4SChen Yugang 
3347a04f3a4SChen Yugang     // step 2 : get ME Major and Minor numbers from its DBUS property
33532825a23SAppaRao Puli     std::string meVersion;
33632825a23SAppaRao Puli     if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
3377a04f3a4SChen Yugang     {
33832825a23SAppaRao Puli         return false;
33932825a23SAppaRao Puli     }
3407a04f3a4SChen Yugang     std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
3417a04f3a4SChen Yugang     constexpr size_t matchedPhosphor = 6;
3427a04f3a4SChen Yugang     std::smatch results;
343d46cb42bSAppaRao Puli     if (std::regex_match(meVersion, results, pattern1))
3447a04f3a4SChen Yugang     {
3457a04f3a4SChen Yugang         if (results.size() == matchedPhosphor)
3467a04f3a4SChen Yugang         {
3477a04f3a4SChen Yugang             meMajor = static_cast<uint8_t>(std::stoi(results[1]));
3487a04f3a4SChen Yugang             meMinor = static_cast<uint8_t>(std::stoi(results[2]));
3497a04f3a4SChen Yugang         }
3507a04f3a4SChen Yugang     }
3517a04f3a4SChen Yugang     return true;
3527a04f3a4SChen Yugang }
3537a04f3a4SChen Yugang 
3547a04f3a4SChen Yugang ipmi::RspType<
3557a04f3a4SChen Yugang     std::variant<std::string,
3567a04f3a4SChen Yugang                  std::tuple<uint8_t, std::array<uint8_t, 2>,
3577a04f3a4SChen Yugang                             std::array<uint8_t, 2>, std::array<uint8_t, 2>,
3587a04f3a4SChen Yugang                             std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
3597a04f3a4SChen Yugang                  std::tuple<uint8_t, std::array<uint8_t, 2>>>>
360e99e7ed3SAppaRao Puli     ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
361e99e7ed3SAppaRao Puli                          std::optional<uint8_t> countToRead,
362d46cb42bSAppaRao Puli                          std::optional<uint8_t> offset)
3637a04f3a4SChen Yugang {
3647a04f3a4SChen Yugang     if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
3657a04f3a4SChen Yugang     {
3667a04f3a4SChen Yugang         return ipmi::responseInvalidFieldRequest();
367a835eaa0SJia, Chunhui     }
368a835eaa0SJia, Chunhui 
369a835eaa0SJia, Chunhui     // handle OEM command items
3707a04f3a4SChen Yugang     switch (OEMDevEntityType(entityType))
371a835eaa0SJia, Chunhui     {
372a835eaa0SJia, Chunhui         case OEMDevEntityType::biosId:
373a835eaa0SJia, Chunhui         {
374d46cb42bSAppaRao Puli             // Byte 2&3, Only used with selecting BIOS
375d46cb42bSAppaRao Puli             if (!countToRead || !offset)
376d46cb42bSAppaRao Puli             {
377d46cb42bSAppaRao Puli                 return ipmi::responseReqDataLenInvalid();
378d46cb42bSAppaRao Puli             }
379d46cb42bSAppaRao Puli 
38015419dd5SVernon Mauery             std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3812742b85cSYong Li             std::string service =
382899bfd15SChalapathi                 getService(*dbus, biosVersionIntf, biosActiveObjPath);
383a835eaa0SJia, Chunhui             try
384a835eaa0SJia, Chunhui             {
3852742b85cSYong Li                 Value variant =
386899bfd15SChalapathi                     getDbusProperty(*dbus, service, biosActiveObjPath,
3872742b85cSYong Li                                     biosVersionIntf, biosVersionProp);
3888166c8d7SVernon Mauery                 std::string& idString = std::get<std::string>(variant);
389d46cb42bSAppaRao Puli                 if (*offset >= idString.size())
390a835eaa0SJia, Chunhui                 {
3917a04f3a4SChen Yugang                     return ipmi::responseParmOutOfRange();
392a835eaa0SJia, Chunhui                 }
393a835eaa0SJia, Chunhui                 size_t length = 0;
394d46cb42bSAppaRao Puli                 if (*countToRead > (idString.size() - *offset))
395a835eaa0SJia, Chunhui                 {
396d46cb42bSAppaRao Puli                     length = idString.size() - *offset;
397a835eaa0SJia, Chunhui                 }
398a835eaa0SJia, Chunhui                 else
399a835eaa0SJia, Chunhui                 {
400d46cb42bSAppaRao Puli                     length = *countToRead;
401a835eaa0SJia, Chunhui                 }
4027a04f3a4SChen Yugang 
4037a04f3a4SChen Yugang                 std::string readBuf = {0};
4047a04f3a4SChen Yugang                 readBuf.resize(length);
405d46cb42bSAppaRao Puli                 std::copy_n(idString.begin() + *offset, length,
4067a04f3a4SChen Yugang                             (readBuf.begin()));
4077a04f3a4SChen Yugang                 return ipmi::responseSuccess(readBuf);
408a835eaa0SJia, Chunhui             }
4098166c8d7SVernon Mauery             catch (std::bad_variant_access& e)
410a835eaa0SJia, Chunhui             {
4117a04f3a4SChen Yugang                 return ipmi::responseUnspecifiedError();
412a835eaa0SJia, Chunhui             }
413a835eaa0SJia, Chunhui         }
414a835eaa0SJia, Chunhui         break;
415a835eaa0SJia, Chunhui 
416a835eaa0SJia, Chunhui         case OEMDevEntityType::devVer:
4177a04f3a4SChen Yugang         {
418d46cb42bSAppaRao Puli             // Byte 2&3, Only used with selecting BIOS
419d46cb42bSAppaRao Puli             if (countToRead || offset)
420d46cb42bSAppaRao Puli             {
421d46cb42bSAppaRao Puli                 return ipmi::responseReqDataLenInvalid();
422d46cb42bSAppaRao Puli             }
423d46cb42bSAppaRao Puli 
4247a04f3a4SChen Yugang             constexpr const size_t verLen = 2;
4257a04f3a4SChen Yugang             constexpr const size_t verTotalLen = 10;
4267a04f3a4SChen Yugang             std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
4277a04f3a4SChen Yugang             std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
4287a04f3a4SChen Yugang             std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
4297a04f3a4SChen Yugang             std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
4307a04f3a4SChen Yugang             std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
4317a04f3a4SChen Yugang             // data0/1: BMC version number; data6/7: ME version number
4327a04f3a4SChen Yugang             // the others: HSC0/1/2 version number, not avaible.
433e99e7ed3SAppaRao Puli             if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
4347a04f3a4SChen Yugang             {
4357a04f3a4SChen Yugang                 return ipmi::responseUnspecifiedError();
436a835eaa0SJia, Chunhui             }
4377a04f3a4SChen Yugang             return ipmi::responseSuccess(
4387a04f3a4SChen Yugang                 std::tuple<
4397a04f3a4SChen Yugang                     uint8_t, std::array<uint8_t, verLen>,
4407a04f3a4SChen Yugang                     std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
4417a04f3a4SChen Yugang                     std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
4427a04f3a4SChen Yugang                     verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
4437a04f3a4SChen Yugang         }
4447a04f3a4SChen Yugang         break;
4457a04f3a4SChen Yugang 
4467a04f3a4SChen Yugang         case OEMDevEntityType::sdrVer:
4477a04f3a4SChen Yugang         {
448d46cb42bSAppaRao Puli             // Byte 2&3, Only used with selecting BIOS
449d46cb42bSAppaRao Puli             if (countToRead || offset)
450d46cb42bSAppaRao Puli             {
451d46cb42bSAppaRao Puli                 return ipmi::responseReqDataLenInvalid();
452d46cb42bSAppaRao Puli             }
453d46cb42bSAppaRao Puli 
4547a04f3a4SChen Yugang             constexpr const size_t sdrLen = 2;
4557a04f3a4SChen Yugang             std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
4567a04f3a4SChen Yugang             return ipmi::responseSuccess(
4577a04f3a4SChen Yugang                 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
4587a04f3a4SChen Yugang                                                                  readBuf});
4597a04f3a4SChen Yugang         }
4607a04f3a4SChen Yugang         break;
4617a04f3a4SChen Yugang 
4627a04f3a4SChen Yugang         default:
4637a04f3a4SChen Yugang             return ipmi::responseInvalidFieldRequest();
4647a04f3a4SChen Yugang     }
465a835eaa0SJia, Chunhui }
466a835eaa0SJia, Chunhui 
467a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
468a835eaa0SJia, Chunhui                             ipmi_request_t request, ipmi_response_t response,
469a835eaa0SJia, Chunhui                             ipmi_data_len_t dataLen, ipmi_context_t context)
470a835eaa0SJia, Chunhui {
471a835eaa0SJia, Chunhui     if (*dataLen != 0)
472a835eaa0SJia, Chunhui     {
47364796041SJason M. Bills         *dataLen = 0;
474a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
475a835eaa0SJia, Chunhui     }
476a835eaa0SJia, Chunhui 
477a835eaa0SJia, Chunhui     *dataLen = 1;
478a835eaa0SJia, Chunhui     uint8_t* res = reinterpret_cast<uint8_t*>(response);
479a835eaa0SJia, Chunhui     // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
480a835eaa0SJia, Chunhui     // AIC is available so that BIOS will not timeout repeatly which leads to
481a835eaa0SJia, Chunhui     // slow booting.
482a835eaa0SJia, Chunhui     *res = 0; // Byte1=Count of SlotPosition/FruID records.
483a835eaa0SJia, Chunhui     return IPMI_CC_OK;
484a835eaa0SJia, Chunhui }
485a835eaa0SJia, Chunhui 
48664796041SJason M. Bills ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
48764796041SJason M. Bills                                        ipmi_request_t request,
48864796041SJason M. Bills                                        ipmi_response_t response,
48964796041SJason M. Bills                                        ipmi_data_len_t dataLen,
49064796041SJason M. Bills                                        ipmi_context_t context)
491a835eaa0SJia, Chunhui {
49264796041SJason M. Bills     GetPowerRestoreDelayRes* resp =
49364796041SJason M. Bills         reinterpret_cast<GetPowerRestoreDelayRes*>(response);
49464796041SJason M. Bills 
49564796041SJason M. Bills     if (*dataLen != 0)
49664796041SJason M. Bills     {
49764796041SJason M. Bills         *dataLen = 0;
49864796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
499a835eaa0SJia, Chunhui     }
500a835eaa0SJia, Chunhui 
50115419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
50264796041SJason M. Bills     std::string service =
50315419dd5SVernon Mauery         getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
50464796041SJason M. Bills     Value variant =
50515419dd5SVernon Mauery         getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
50664796041SJason M. Bills                         powerRestoreDelayIntf, powerRestoreDelayProp);
50764796041SJason M. Bills 
5088166c8d7SVernon Mauery     uint16_t delay = std::get<uint16_t>(variant);
50964796041SJason M. Bills     resp->byteLSB = delay;
51064796041SJason M. Bills     resp->byteMSB = delay >> 8;
51164796041SJason M. Bills 
51264796041SJason M. Bills     *dataLen = sizeof(GetPowerRestoreDelayRes);
51364796041SJason M. Bills 
51464796041SJason M. Bills     return IPMI_CC_OK;
51564796041SJason M. Bills }
51664796041SJason M. Bills 
517cc49b54bSJia, Chunhui static uint8_t bcdToDec(uint8_t val)
518cc49b54bSJia, Chunhui {
519cc49b54bSJia, Chunhui     return ((val / 16 * 10) + (val % 16));
520cc49b54bSJia, Chunhui }
521cc49b54bSJia, Chunhui 
522cc49b54bSJia, Chunhui // Allows an update utility or system BIOS to send the status of an embedded
523cc49b54bSJia, Chunhui // firmware update attempt to the BMC. After received, BMC will create a logging
524cc49b54bSJia, Chunhui // record.
525cc49b54bSJia, Chunhui ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
526cc49b54bSJia, Chunhui                                                uint8_t majorRevision,
527cc49b54bSJia, Chunhui                                                uint8_t minorRevision,
528cc49b54bSJia, Chunhui                                                uint32_t auxInfo)
529cc49b54bSJia, Chunhui {
530cc49b54bSJia, Chunhui     std::string firmware;
531dc24927fSJason M. Bills     int instance = (target & targetInstanceMask) >> targetInstanceShift;
532cc49b54bSJia, Chunhui     target = (target & selEvtTargetMask) >> selEvtTargetShift;
533cc49b54bSJia, Chunhui 
534cc49b54bSJia, Chunhui     /* make sure the status is 0, 1, or 2 as per the spec */
535cc49b54bSJia, Chunhui     if (status > 2)
536cc49b54bSJia, Chunhui     {
537cc49b54bSJia, Chunhui         return ipmi::response(ipmi::ccInvalidFieldRequest);
538cc49b54bSJia, Chunhui     }
539dc24927fSJason M. Bills     /* make sure the target is 0, 1, 2, or 4 as per the spec */
540dc24927fSJason M. Bills     if (target > 4 || target == 3)
541dc24927fSJason M. Bills     {
542dc24927fSJason M. Bills         return ipmi::response(ipmi::ccInvalidFieldRequest);
543dc24927fSJason M. Bills     }
544cc49b54bSJia, Chunhui     /*orignal OEM command is to record OEM SEL.
545cc49b54bSJia, Chunhui     But openbmc does not support OEM SEL, so we redirect it to redfish event
546cc49b54bSJia, Chunhui     logging. */
547cc49b54bSJia, Chunhui     std::string buildInfo;
548cc49b54bSJia, Chunhui     std::string action;
549cc49b54bSJia, Chunhui     switch (FWUpdateTarget(target))
550cc49b54bSJia, Chunhui     {
551cc49b54bSJia, Chunhui         case FWUpdateTarget::targetBMC:
552cc49b54bSJia, Chunhui             firmware = "BMC";
553dc24927fSJason M. Bills             buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
554cc49b54bSJia, Chunhui                         std::to_string(bcdToDec(minorRevision)) + // BCD encoded
555cc49b54bSJia, Chunhui                         " BuildID: " + std::to_string(auxInfo);
556cc49b54bSJia, Chunhui             buildInfo += std::to_string(auxInfo);
557cc49b54bSJia, Chunhui             break;
558cc49b54bSJia, Chunhui         case FWUpdateTarget::targetBIOS:
559cc49b54bSJia, Chunhui             firmware = "BIOS";
560cc49b54bSJia, Chunhui             buildInfo =
561cc49b54bSJia, Chunhui                 "major: " +
562cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
563cc49b54bSJia, Chunhui                 " minor: " +
564cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
565cc49b54bSJia, Chunhui                 " ReleaseNumber: " +                      // ASCII encoded
566cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
567cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
568cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
569cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
570cc49b54bSJia, Chunhui             break;
571cc49b54bSJia, Chunhui         case FWUpdateTarget::targetME:
572cc49b54bSJia, Chunhui             firmware = "ME";
573cc49b54bSJia, Chunhui             buildInfo =
574cc49b54bSJia, Chunhui                 "major: " + std::to_string(majorRevision) + " minor1: " +
575cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
576cc49b54bSJia, Chunhui                 " minor2: " +
577cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
578cc49b54bSJia, Chunhui                 " build1: " +
579cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
580cc49b54bSJia, Chunhui                 " build2: " +
581cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
582cc49b54bSJia, Chunhui             break;
583cc49b54bSJia, Chunhui         case FWUpdateTarget::targetOEMEWS:
584cc49b54bSJia, Chunhui             firmware = "EWS";
585dc24927fSJason M. Bills             buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
586cc49b54bSJia, Chunhui                         std::to_string(bcdToDec(minorRevision)) + // BCD encoded
587cc49b54bSJia, Chunhui                         " BuildID: " + std::to_string(auxInfo);
588cc49b54bSJia, Chunhui             break;
589cc49b54bSJia, Chunhui     }
590cc49b54bSJia, Chunhui 
591dc24927fSJason M. Bills     static const std::string openBMCMessageRegistryVersion("0.1");
592dc24927fSJason M. Bills     std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
593dc24927fSJason M. Bills 
594cc49b54bSJia, Chunhui     switch (status)
595cc49b54bSJia, Chunhui     {
596cc49b54bSJia, Chunhui         case 0x0:
597cc49b54bSJia, Chunhui             action = "update started";
598dc24927fSJason M. Bills             redfishMsgID += ".FirmwareUpdateStarted";
599cc49b54bSJia, Chunhui             break;
600cc49b54bSJia, Chunhui         case 0x1:
601cc49b54bSJia, Chunhui             action = "update completed successfully";
602dc24927fSJason M. Bills             redfishMsgID += ".FirmwareUpdateCompleted";
603cc49b54bSJia, Chunhui             break;
604cc49b54bSJia, Chunhui         case 0x2:
605cc49b54bSJia, Chunhui             action = "update failure";
606dc24927fSJason M. Bills             redfishMsgID += ".FirmwareUpdateFailed";
607cc49b54bSJia, Chunhui             break;
608cc49b54bSJia, Chunhui         default:
609cc49b54bSJia, Chunhui             action = "unknown";
610cc49b54bSJia, Chunhui             break;
611cc49b54bSJia, Chunhui     }
612cc49b54bSJia, Chunhui 
613dc24927fSJason M. Bills     std::string firmwareInstanceStr =
614dc24927fSJason M. Bills         firmware + " instance: " + std::to_string(instance);
615dc24927fSJason M. Bills     std::string message("[firmware update] " + firmwareInstanceStr +
616cc49b54bSJia, Chunhui                         " status: <" + action + "> " + buildInfo);
617cc49b54bSJia, Chunhui 
618cc49b54bSJia, Chunhui     sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
619dc24927fSJason M. Bills                     "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
620dc24927fSJason M. Bills                     "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
621dc24927fSJason M. Bills                     buildInfo.c_str(), NULL);
622cc49b54bSJia, Chunhui     return ipmi::responseSuccess();
623cc49b54bSJia, Chunhui }
624cc49b54bSJia, Chunhui 
6252b664d5aSRajashekar Gade Reddy ipmi::RspType<uint8_t, std::vector<uint8_t>>
6262b664d5aSRajashekar Gade Reddy     ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
6272b664d5aSRajashekar Gade Reddy                     uint2_t slotNumber, uint3_t baseBoardSlotNum,
6282b664d5aSRajashekar Gade Reddy                     uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
6292b664d5aSRajashekar Gade Reddy                     uint8_t netFn, uint8_t cmd,
6302b664d5aSRajashekar Gade Reddy                     std::optional<std::vector<uint8_t>> writeData)
6312b664d5aSRajashekar Gade Reddy {
6322b664d5aSRajashekar Gade Reddy     if (reserved1 || reserved2)
6332b664d5aSRajashekar Gade Reddy     {
6342b664d5aSRajashekar Gade Reddy         return ipmi::responseInvalidFieldRequest();
6352b664d5aSRajashekar Gade Reddy     }
6362b664d5aSRajashekar Gade Reddy 
6372b664d5aSRajashekar Gade Reddy     boost::system::error_code ec;
6382b664d5aSRajashekar Gade Reddy     using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
6392b664d5aSRajashekar Gade Reddy                                     std::vector<uint8_t>>;
6402b664d5aSRajashekar Gade Reddy     ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
6412b664d5aSRajashekar Gade Reddy         ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
6422b664d5aSRajashekar Gade Reddy         "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
6432b664d5aSRajashekar Gade Reddy         "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
6442b664d5aSRajashekar Gade Reddy         static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
6452b664d5aSRajashekar Gade Reddy         *writeData);
6462b664d5aSRajashekar Gade Reddy     if (ec)
6472b664d5aSRajashekar Gade Reddy     {
6482b664d5aSRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::ERR>(
6492b664d5aSRajashekar Gade Reddy             "Failed to call dbus method SlotIpmbRequest");
6502b664d5aSRajashekar Gade Reddy         return ipmi::responseUnspecifiedError();
6512b664d5aSRajashekar Gade Reddy     }
6522b664d5aSRajashekar Gade Reddy 
6532b664d5aSRajashekar Gade Reddy     std::vector<uint8_t> dataReceived(0);
6542b664d5aSRajashekar Gade Reddy     int status = -1;
6552b664d5aSRajashekar Gade Reddy     uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
6562b664d5aSRajashekar Gade Reddy 
6572b664d5aSRajashekar Gade Reddy     std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
6582b664d5aSRajashekar Gade Reddy 
6592b664d5aSRajashekar Gade Reddy     if (status)
6602b664d5aSRajashekar Gade Reddy     {
6612b664d5aSRajashekar Gade Reddy         phosphor::logging::log<phosphor::logging::level::ERR>(
6622b664d5aSRajashekar Gade Reddy             "Failed to get response from SlotIpmbRequest");
6632b664d5aSRajashekar Gade Reddy         return ipmi::responseResponseError();
6642b664d5aSRajashekar Gade Reddy     }
6652b664d5aSRajashekar Gade Reddy     return ipmi::responseSuccess(cc, dataReceived);
6662b664d5aSRajashekar Gade Reddy }
6672b664d5aSRajashekar Gade Reddy 
66864796041SJason M. Bills ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
66964796041SJason M. Bills                                        ipmi_request_t request,
67064796041SJason M. Bills                                        ipmi_response_t response,
67164796041SJason M. Bills                                        ipmi_data_len_t dataLen,
67264796041SJason M. Bills                                        ipmi_context_t context)
67364796041SJason M. Bills {
67464796041SJason M. Bills     SetPowerRestoreDelayReq* data =
67564796041SJason M. Bills         reinterpret_cast<SetPowerRestoreDelayReq*>(request);
67664796041SJason M. Bills     uint16_t delay = 0;
67764796041SJason M. Bills 
67864796041SJason M. Bills     if (*dataLen != sizeof(SetPowerRestoreDelayReq))
67964796041SJason M. Bills     {
68064796041SJason M. Bills         *dataLen = 0;
68164796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
68264796041SJason M. Bills     }
68364796041SJason M. Bills     delay = data->byteMSB;
68464796041SJason M. Bills     delay = (delay << 8) | data->byteLSB;
68515419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
68664796041SJason M. Bills     std::string service =
68715419dd5SVernon Mauery         getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
68815419dd5SVernon Mauery     setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
68964796041SJason M. Bills                     powerRestoreDelayIntf, powerRestoreDelayProp, delay);
69064796041SJason M. Bills     *dataLen = 0;
69164796041SJason M. Bills 
69264796041SJason M. Bills     return IPMI_CC_OK;
69364796041SJason M. Bills }
69464796041SJason M. Bills 
69542bd9c8eSJason M. Bills static bool cpuPresent(const std::string& cpuName)
69664796041SJason M. Bills {
69742bd9c8eSJason M. Bills     static constexpr const char* cpuPresencePathPrefix =
69842bd9c8eSJason M. Bills         "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
69942bd9c8eSJason M. Bills     static constexpr const char* cpuPresenceIntf =
70042bd9c8eSJason M. Bills         "xyz.openbmc_project.Inventory.Item";
70142bd9c8eSJason M. Bills     std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
70242bd9c8eSJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
70342bd9c8eSJason M. Bills     try
70442bd9c8eSJason M. Bills     {
70542bd9c8eSJason M. Bills         auto service =
70642bd9c8eSJason M. Bills             ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
70764796041SJason M. Bills 
70842bd9c8eSJason M. Bills         ipmi::Value result = ipmi::getDbusProperty(
70942bd9c8eSJason M. Bills             *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
71042bd9c8eSJason M. Bills         return std::get<bool>(result);
71142bd9c8eSJason M. Bills     }
71242bd9c8eSJason M. Bills     catch (const std::exception& e)
71364796041SJason M. Bills     {
71442bd9c8eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::INFO>(
71542bd9c8eSJason M. Bills             "Cannot find processor presence",
71642bd9c8eSJason M. Bills             phosphor::logging::entry("NAME=%s", cpuName.c_str()));
71742bd9c8eSJason M. Bills         return false;
71842bd9c8eSJason M. Bills     }
71964796041SJason M. Bills }
72064796041SJason M. Bills 
72142bd9c8eSJason M. Bills ipmi::RspType<bool,    // CATERR Reset Enabled
72242bd9c8eSJason M. Bills               bool,    // ERR2 Reset Enabled
72342bd9c8eSJason M. Bills               uint6_t, // reserved
72442bd9c8eSJason M. Bills               uint8_t, // reserved, returns 0x3F
72542bd9c8eSJason M. Bills               uint6_t, // CPU1 CATERR Count
72642bd9c8eSJason M. Bills               uint2_t, // CPU1 Status
72742bd9c8eSJason M. Bills               uint6_t, // CPU2 CATERR Count
72842bd9c8eSJason M. Bills               uint2_t, // CPU2 Status
72942bd9c8eSJason M. Bills               uint6_t, // CPU3 CATERR Count
73042bd9c8eSJason M. Bills               uint2_t, // CPU3 Status
73142bd9c8eSJason M. Bills               uint6_t, // CPU4 CATERR Count
73242bd9c8eSJason M. Bills               uint2_t, // CPU4 Status
73342bd9c8eSJason M. Bills               uint8_t  // Crashdump Count
73442bd9c8eSJason M. Bills               >
73542bd9c8eSJason M. Bills     ipmiOEMGetProcessorErrConfig()
73642bd9c8eSJason M. Bills {
73742bd9c8eSJason M. Bills     bool resetOnCATERR = false;
73842bd9c8eSJason M. Bills     bool resetOnERR2 = false;
73942bd9c8eSJason M. Bills     uint6_t cpu1CATERRCount = 0;
74042bd9c8eSJason M. Bills     uint6_t cpu2CATERRCount = 0;
74142bd9c8eSJason M. Bills     uint6_t cpu3CATERRCount = 0;
74242bd9c8eSJason M. Bills     uint6_t cpu4CATERRCount = 0;
74342bd9c8eSJason M. Bills     uint8_t crashdumpCount = 0;
74442bd9c8eSJason M. Bills     uint2_t cpu1Status =
74542bd9c8eSJason M. Bills         cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
74642bd9c8eSJason M. Bills     uint2_t cpu2Status =
74742bd9c8eSJason M. Bills         cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
74842bd9c8eSJason M. Bills     uint2_t cpu3Status =
74942bd9c8eSJason M. Bills         cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
75042bd9c8eSJason M. Bills     uint2_t cpu4Status =
75142bd9c8eSJason M. Bills         cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
75264796041SJason M. Bills 
75342bd9c8eSJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
75442bd9c8eSJason M. Bills     try
75542bd9c8eSJason M. Bills     {
75642bd9c8eSJason M. Bills         auto service = ipmi::getService(*busp, processorErrConfigIntf,
75742bd9c8eSJason M. Bills                                         processorErrConfigObjPath);
75864796041SJason M. Bills 
75942bd9c8eSJason M. Bills         ipmi::PropertyMap result = ipmi::getAllDbusProperties(
76042bd9c8eSJason M. Bills             *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
76142bd9c8eSJason M. Bills         resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
76242bd9c8eSJason M. Bills         resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
76342bd9c8eSJason M. Bills         cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
76442bd9c8eSJason M. Bills         cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
76542bd9c8eSJason M. Bills         cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
76642bd9c8eSJason M. Bills         cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
76742bd9c8eSJason M. Bills         crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
76842bd9c8eSJason M. Bills     }
76942bd9c8eSJason M. Bills     catch (const std::exception& e)
77042bd9c8eSJason M. Bills     {
77142bd9c8eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
77242bd9c8eSJason M. Bills             "Failed to fetch processor error config",
77342bd9c8eSJason M. Bills             phosphor::logging::entry("ERROR=%s", e.what()));
77442bd9c8eSJason M. Bills         return ipmi::responseUnspecifiedError();
77542bd9c8eSJason M. Bills     }
77664796041SJason M. Bills 
77742bd9c8eSJason M. Bills     return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
77842bd9c8eSJason M. Bills                                  cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
77942bd9c8eSJason M. Bills                                  cpu2Status, cpu3CATERRCount, cpu3Status,
78042bd9c8eSJason M. Bills                                  cpu4CATERRCount, cpu4Status, crashdumpCount);
78142bd9c8eSJason M. Bills }
78242bd9c8eSJason M. Bills 
78342bd9c8eSJason M. Bills ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
78442bd9c8eSJason M. Bills     bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
78542bd9c8eSJason M. Bills     std::optional<bool> clearCPUErrorCount,
78642bd9c8eSJason M. Bills     std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
78742bd9c8eSJason M. Bills {
78842bd9c8eSJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
78964796041SJason M. Bills 
79064796041SJason M. Bills     try
79164796041SJason M. Bills     {
79242bd9c8eSJason M. Bills         auto service = ipmi::getService(*busp, processorErrConfigIntf,
79342bd9c8eSJason M. Bills                                         processorErrConfigObjPath);
79442bd9c8eSJason M. Bills         ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
79542bd9c8eSJason M. Bills                               processorErrConfigIntf, "ResetOnCATERR",
79642bd9c8eSJason M. Bills                               resetOnCATERR);
79742bd9c8eSJason M. Bills         ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
79842bd9c8eSJason M. Bills                               processorErrConfigIntf, "ResetOnERR2",
79942bd9c8eSJason M. Bills                               resetOnERR2);
80042bd9c8eSJason M. Bills         if (clearCPUErrorCount.value_or(false))
80142bd9c8eSJason M. Bills         {
80242bd9c8eSJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
803d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU1",
804d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
80542bd9c8eSJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
806d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU2",
807d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
808d3e19936SJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
809d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU3",
810d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
811d3e19936SJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
812d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU4",
813d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
81464796041SJason M. Bills         }
81542bd9c8eSJason M. Bills         if (clearCrashdumpCount.value_or(false))
81642bd9c8eSJason M. Bills         {
81742bd9c8eSJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
818d3e19936SJason M. Bills                                   processorErrConfigIntf, "CrashdumpCount",
819d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
82042bd9c8eSJason M. Bills         }
82142bd9c8eSJason M. Bills     }
82242bd9c8eSJason M. Bills     catch (std::exception& e)
82364796041SJason M. Bills     {
824bc546679SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(
82542bd9c8eSJason M. Bills             "Failed to set processor error config",
82642bd9c8eSJason M. Bills             phosphor::logging::entry("EXCEPTION=%s", e.what()));
82742bd9c8eSJason M. Bills         return ipmi::responseUnspecifiedError();
82864796041SJason M. Bills     }
82964796041SJason M. Bills 
83042bd9c8eSJason M. Bills     return ipmi::responseSuccess();
83164796041SJason M. Bills }
83264796041SJason M. Bills 
833703922d0SYong Li ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
834703922d0SYong Li                                     ipmi_request_t request,
835703922d0SYong Li                                     ipmi_response_t response,
836703922d0SYong Li                                     ipmi_data_len_t dataLen,
837703922d0SYong Li                                     ipmi_context_t context)
838703922d0SYong Li {
839703922d0SYong Li     GetOEMShutdownPolicyRes* resp =
840703922d0SYong Li         reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
841703922d0SYong Li 
842703922d0SYong Li     if (*dataLen != 0)
843703922d0SYong Li     {
844703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
84545f04988SKuiying Wang             "oem_get_shutdown_policy: invalid input len!");
846703922d0SYong Li         *dataLen = 0;
847703922d0SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
848703922d0SYong Li     }
849703922d0SYong Li 
850703922d0SYong Li     *dataLen = 0;
851703922d0SYong Li 
852703922d0SYong Li     try
853703922d0SYong Li     {
85415419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
855703922d0SYong Li         std::string service =
85615419dd5SVernon Mauery             getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
85715419dd5SVernon Mauery         Value variant = getDbusProperty(
85815419dd5SVernon Mauery             *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
859703922d0SYong Li             oemShutdownPolicyObjPathProp);
8600669d193SYong Li 
8610669d193SYong Li         if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
8620669d193SYong Li                 convertPolicyFromString(std::get<std::string>(variant)) ==
8630669d193SYong Li             sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
8640669d193SYong Li                 NoShutdownOnOCOT)
8650669d193SYong Li         {
8660669d193SYong Li             resp->policy = 0;
8670669d193SYong Li         }
8680669d193SYong Li         else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
8690669d193SYong Li                      convertPolicyFromString(std::get<std::string>(variant)) ==
8700669d193SYong Li                  sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
8710669d193SYong Li                      Policy::ShutdownOnOCOT)
8720669d193SYong Li         {
8730669d193SYong Li             resp->policy = 1;
8740669d193SYong Li         }
8750669d193SYong Li         else
8760669d193SYong Li         {
8770669d193SYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
8780669d193SYong Li                 "oem_set_shutdown_policy: invalid property!",
8790669d193SYong Li                 phosphor::logging::entry(
8800669d193SYong Li                     "PROP=%s", std::get<std::string>(variant).c_str()));
8810669d193SYong Li             return IPMI_CC_UNSPECIFIED_ERROR;
8820669d193SYong Li         }
883703922d0SYong Li         // TODO needs to check if it is multi-node products,
884703922d0SYong Li         // policy is only supported on node 3/4
885703922d0SYong Li         resp->policySupport = shutdownPolicySupported;
886703922d0SYong Li     }
887703922d0SYong Li     catch (sdbusplus::exception_t& e)
888703922d0SYong Li     {
889703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
890703922d0SYong Li         return IPMI_CC_UNSPECIFIED_ERROR;
891703922d0SYong Li     }
892703922d0SYong Li 
893703922d0SYong Li     *dataLen = sizeof(GetOEMShutdownPolicyRes);
894703922d0SYong Li     return IPMI_CC_OK;
895703922d0SYong Li }
896703922d0SYong Li 
897703922d0SYong Li ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
898703922d0SYong Li                                     ipmi_request_t request,
899703922d0SYong Li                                     ipmi_response_t response,
900703922d0SYong Li                                     ipmi_data_len_t dataLen,
901703922d0SYong Li                                     ipmi_context_t context)
902703922d0SYong Li {
903703922d0SYong Li     uint8_t* req = reinterpret_cast<uint8_t*>(request);
9040669d193SYong Li     sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
9050669d193SYong Li         sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
9060669d193SYong Li             NoShutdownOnOCOT;
907703922d0SYong Li 
908703922d0SYong Li     // TODO needs to check if it is multi-node products,
909703922d0SYong Li     // policy is only supported on node 3/4
910703922d0SYong Li     if (*dataLen != 1)
911703922d0SYong Li     {
912703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
913703922d0SYong Li             "oem_set_shutdown_policy: invalid input len!");
914703922d0SYong Li         *dataLen = 0;
915703922d0SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
916703922d0SYong Li     }
917703922d0SYong Li 
918703922d0SYong Li     *dataLen = 0;
919703922d0SYong Li     if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
920703922d0SYong Li     {
921703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
922703922d0SYong Li             "oem_set_shutdown_policy: invalid input!");
923703922d0SYong Li         return IPMI_CC_INVALID_FIELD_REQUEST;
924703922d0SYong Li     }
925703922d0SYong Li 
9260669d193SYong Li     if (*req == noShutdownOnOCOT)
9270669d193SYong Li     {
9280669d193SYong Li         policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
9290669d193SYong Li             Policy::NoShutdownOnOCOT;
9300669d193SYong Li     }
9310669d193SYong Li     else
9320669d193SYong Li     {
9330669d193SYong Li         policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
9340669d193SYong Li             Policy::ShutdownOnOCOT;
9350669d193SYong Li     }
9360669d193SYong Li 
937703922d0SYong Li     try
938703922d0SYong Li     {
93915419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
940703922d0SYong Li         std::string service =
94115419dd5SVernon Mauery             getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
9420669d193SYong Li         setDbusProperty(
94315419dd5SVernon Mauery             *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
9440669d193SYong Li             oemShutdownPolicyObjPathProp,
9450669d193SYong Li             sdbusplus::com::intel::Control::server::convertForMessage(policy));
946703922d0SYong Li     }
947703922d0SYong Li     catch (sdbusplus::exception_t& e)
948703922d0SYong Li     {
949703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
950703922d0SYong Li         return IPMI_CC_UNSPECIFIED_ERROR;
951703922d0SYong Li     }
952703922d0SYong Li 
953703922d0SYong Li     return IPMI_CC_OK;
954703922d0SYong Li }
955703922d0SYong Li 
956d509eb91SSuryakanth Sekar /** @brief implementation for check the DHCP or not in IPv4
957d509eb91SSuryakanth Sekar  *  @param[in] Channel - Channel number
958d509eb91SSuryakanth Sekar  *  @returns true or false.
959d509eb91SSuryakanth Sekar  */
960d509eb91SSuryakanth Sekar static bool isDHCPEnabled(uint8_t Channel)
961d509eb91SSuryakanth Sekar {
962d509eb91SSuryakanth Sekar     try
963d509eb91SSuryakanth Sekar     {
964d509eb91SSuryakanth Sekar         auto ethdevice = getChannelName(Channel);
965d509eb91SSuryakanth Sekar         if (ethdevice.empty())
966d509eb91SSuryakanth Sekar         {
967d509eb91SSuryakanth Sekar             return false;
968d509eb91SSuryakanth Sekar         }
969d509eb91SSuryakanth Sekar         auto ethIP = ethdevice + "/ipv4";
97015419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
971d509eb91SSuryakanth Sekar         auto ethernetObj =
97215419dd5SVernon Mauery             getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
97315419dd5SVernon Mauery         auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
974d509eb91SSuryakanth Sekar                                      networkIPIntf, "Origin");
9758166c8d7SVernon Mauery         if (std::get<std::string>(value) ==
976d509eb91SSuryakanth Sekar             "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
977d509eb91SSuryakanth Sekar         {
978d509eb91SSuryakanth Sekar             return true;
979d509eb91SSuryakanth Sekar         }
980d509eb91SSuryakanth Sekar         else
981d509eb91SSuryakanth Sekar         {
982d509eb91SSuryakanth Sekar             return false;
983d509eb91SSuryakanth Sekar         }
984d509eb91SSuryakanth Sekar     }
985d509eb91SSuryakanth Sekar     catch (sdbusplus::exception_t& e)
986d509eb91SSuryakanth Sekar     {
987d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
988d509eb91SSuryakanth Sekar         return true;
989d509eb91SSuryakanth Sekar     }
990d509eb91SSuryakanth Sekar }
991d509eb91SSuryakanth Sekar 
992d509eb91SSuryakanth Sekar /** @brief implementes for check the DHCP or not in IPv6
993d509eb91SSuryakanth Sekar  *  @param[in] Channel - Channel number
994d509eb91SSuryakanth Sekar  *  @returns true or false.
995d509eb91SSuryakanth Sekar  */
996d509eb91SSuryakanth Sekar static bool isDHCPIPv6Enabled(uint8_t Channel)
997d509eb91SSuryakanth Sekar {
998d509eb91SSuryakanth Sekar 
999d509eb91SSuryakanth Sekar     try
1000d509eb91SSuryakanth Sekar     {
1001d509eb91SSuryakanth Sekar         auto ethdevice = getChannelName(Channel);
1002d509eb91SSuryakanth Sekar         if (ethdevice.empty())
1003d509eb91SSuryakanth Sekar         {
1004d509eb91SSuryakanth Sekar             return false;
1005d509eb91SSuryakanth Sekar         }
1006d509eb91SSuryakanth Sekar         auto ethIP = ethdevice + "/ipv6";
100715419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1008d509eb91SSuryakanth Sekar         auto objectInfo =
100915419dd5SVernon Mauery             getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
101015419dd5SVernon Mauery         auto properties = getAllDbusProperties(*dbus, objectInfo.second,
1011d509eb91SSuryakanth Sekar                                                objectInfo.first, networkIPIntf);
10128166c8d7SVernon Mauery         if (std::get<std::string>(properties["Origin"]) ==
1013d509eb91SSuryakanth Sekar             "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1014d509eb91SSuryakanth Sekar         {
1015d509eb91SSuryakanth Sekar             return true;
1016d509eb91SSuryakanth Sekar         }
1017d509eb91SSuryakanth Sekar         else
1018d509eb91SSuryakanth Sekar         {
1019d509eb91SSuryakanth Sekar             return false;
1020d509eb91SSuryakanth Sekar         }
1021d509eb91SSuryakanth Sekar     }
1022d509eb91SSuryakanth Sekar     catch (sdbusplus::exception_t& e)
1023d509eb91SSuryakanth Sekar     {
1024d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1025d509eb91SSuryakanth Sekar         return true;
1026d509eb91SSuryakanth Sekar     }
1027d509eb91SSuryakanth Sekar }
1028d509eb91SSuryakanth Sekar 
1029d509eb91SSuryakanth Sekar /** @brief implementes the creating of default new user
1030d509eb91SSuryakanth Sekar  *  @param[in] userName - new username in 16 bytes.
1031d509eb91SSuryakanth Sekar  *  @param[in] userPassword - new password in 20 bytes
1032d509eb91SSuryakanth Sekar  *  @returns ipmi completion code.
1033d509eb91SSuryakanth Sekar  */
1034d509eb91SSuryakanth Sekar ipmi::RspType<> ipmiOEMSetUser2Activation(
1035d509eb91SSuryakanth Sekar     std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1036d509eb91SSuryakanth Sekar     std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1037d509eb91SSuryakanth Sekar {
1038d509eb91SSuryakanth Sekar     bool userState = false;
1039d509eb91SSuryakanth Sekar     // Check for System Interface not exist and LAN should be static
1040d509eb91SSuryakanth Sekar     for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1041d509eb91SSuryakanth Sekar     {
1042d509eb91SSuryakanth Sekar         ChannelInfo chInfo;
1043d509eb91SSuryakanth Sekar         try
1044d509eb91SSuryakanth Sekar         {
1045d509eb91SSuryakanth Sekar             getChannelInfo(channel, chInfo);
1046d509eb91SSuryakanth Sekar         }
1047d509eb91SSuryakanth Sekar         catch (sdbusplus::exception_t& e)
1048d509eb91SSuryakanth Sekar         {
1049d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
1050d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1051d509eb91SSuryakanth Sekar                 phosphor::logging::entry("MSG: %s", e.description()));
1052d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccUnspecifiedError);
1053d509eb91SSuryakanth Sekar         }
1054d509eb91SSuryakanth Sekar         if (chInfo.mediumType ==
1055d509eb91SSuryakanth Sekar             static_cast<uint8_t>(EChannelMediumType::systemInterface))
1056d509eb91SSuryakanth Sekar         {
1057d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
1058d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: system interface  exist .");
1059d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
1060d509eb91SSuryakanth Sekar         }
1061d509eb91SSuryakanth Sekar         else
1062d509eb91SSuryakanth Sekar         {
1063d509eb91SSuryakanth Sekar 
1064d509eb91SSuryakanth Sekar             if (chInfo.mediumType ==
1065d509eb91SSuryakanth Sekar                 static_cast<uint8_t>(EChannelMediumType::lan8032))
1066d509eb91SSuryakanth Sekar             {
1067d509eb91SSuryakanth Sekar                 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1068d509eb91SSuryakanth Sekar                 {
1069d509eb91SSuryakanth Sekar                     phosphor::logging::log<phosphor::logging::level::ERR>(
1070d509eb91SSuryakanth Sekar                         "ipmiOEMSetUser2Activation: DHCP enabled .");
1071d509eb91SSuryakanth Sekar                     return ipmi::response(ipmi::ccCommandNotAvailable);
1072d509eb91SSuryakanth Sekar                 }
1073d509eb91SSuryakanth Sekar             }
1074d509eb91SSuryakanth Sekar         }
1075d509eb91SSuryakanth Sekar     }
1076d509eb91SSuryakanth Sekar     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1077d509eb91SSuryakanth Sekar     if (ipmi::ccSuccess ==
1078d509eb91SSuryakanth Sekar         ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1079d509eb91SSuryakanth Sekar     {
1080d509eb91SSuryakanth Sekar         if (enabledUsers > 1)
1081d509eb91SSuryakanth Sekar         {
1082d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
1083d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1084d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
1085d509eb91SSuryakanth Sekar         }
1086d509eb91SSuryakanth Sekar         // Check the user 2 is enabled or not
1087d509eb91SSuryakanth Sekar         ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1088d509eb91SSuryakanth Sekar         if (userState == true)
1089d509eb91SSuryakanth Sekar         {
1090d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
1091d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1092d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
1093d509eb91SSuryakanth Sekar         }
1094d509eb91SSuryakanth Sekar     }
1095d509eb91SSuryakanth Sekar     else
1096d509eb91SSuryakanth Sekar     {
1097d509eb91SSuryakanth Sekar         return ipmi::response(ipmi::ccUnspecifiedError);
1098d509eb91SSuryakanth Sekar     }
1099d509eb91SSuryakanth Sekar 
1100d509eb91SSuryakanth Sekar #if BYTE_ORDER == LITTLE_ENDIAN
1101d509eb91SSuryakanth Sekar     PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1102d509eb91SSuryakanth Sekar #endif
1103d509eb91SSuryakanth Sekar #if BYTE_ORDER == BIG_ENDIAN
1104d509eb91SSuryakanth Sekar     PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1105d509eb91SSuryakanth Sekar #endif
1106d509eb91SSuryakanth Sekar 
1107037cabddSVernon Mauery     // ipmiUserSetUserName correctly handles char*, possibly non-null
1108037cabddSVernon Mauery     // terminated strings using ipmiMaxUserName size
11093fbe8d2aSJayaprakash Mutyala     size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
11103fbe8d2aSJayaprakash Mutyala                              sizeof(userName));
11113fbe8d2aSJayaprakash Mutyala     const std::string userNameRaw(
11123fbe8d2aSJayaprakash Mutyala         reinterpret_cast<const char*>(userName.data()), nameLen);
11131429d4f1Sjayaprakash Mutyala 
1114037cabddSVernon Mauery     if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
1115d509eb91SSuryakanth Sekar     {
1116d509eb91SSuryakanth Sekar         if (ipmi::ccSuccess ==
1117d509eb91SSuryakanth Sekar             ipmiUserSetUserPassword(
1118d509eb91SSuryakanth Sekar                 ipmiDefaultUserId,
1119d509eb91SSuryakanth Sekar                 reinterpret_cast<const char*>(userPassword.data())))
1120d509eb91SSuryakanth Sekar         {
1121d509eb91SSuryakanth Sekar             if (ipmi::ccSuccess ==
1122d509eb91SSuryakanth Sekar                 ipmiUserSetPrivilegeAccess(
1123d509eb91SSuryakanth Sekar                     ipmiDefaultUserId,
1124d509eb91SSuryakanth Sekar                     static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1125d509eb91SSuryakanth Sekar                     privAccess, true))
1126d509eb91SSuryakanth Sekar             {
1127d509eb91SSuryakanth Sekar                 phosphor::logging::log<phosphor::logging::level::INFO>(
1128d509eb91SSuryakanth Sekar                     "ipmiOEMSetUser2Activation: user created successfully ");
11299420416aSJayaprakash Mutyala                 OPENSSL_cleanse(userPassword.data(), userPassword.size());
11309420416aSJayaprakash Mutyala 
1131d509eb91SSuryakanth Sekar                 return ipmi::responseSuccess();
1132d509eb91SSuryakanth Sekar             }
1133d509eb91SSuryakanth Sekar         }
1134d509eb91SSuryakanth Sekar         // we need to delete  the default user id which added in this command as
1135d509eb91SSuryakanth Sekar         // password / priv setting is failed.
11363fbe8d2aSJayaprakash Mutyala         ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
1137d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(
1138d509eb91SSuryakanth Sekar             "ipmiOEMSetUser2Activation: password / priv setting is failed.");
11399420416aSJayaprakash Mutyala         OPENSSL_cleanse(userPassword.data(), userPassword.size());
1140d509eb91SSuryakanth Sekar     }
1141d509eb91SSuryakanth Sekar     else
1142d509eb91SSuryakanth Sekar     {
1143d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(
1144d509eb91SSuryakanth Sekar             "ipmiOEMSetUser2Activation: Setting username failed.");
1145d509eb91SSuryakanth Sekar     }
1146d509eb91SSuryakanth Sekar 
1147d509eb91SSuryakanth Sekar     return ipmi::response(ipmi::ccCommandNotAvailable);
1148d509eb91SSuryakanth Sekar }
1149d509eb91SSuryakanth Sekar 
1150822b0b40SSuryakanth Sekar /** @brief implementes executing the linux command
1151822b0b40SSuryakanth Sekar  *  @param[in] linux command
1152822b0b40SSuryakanth Sekar  *  @returns status
1153822b0b40SSuryakanth Sekar  */
1154822b0b40SSuryakanth Sekar 
1155822b0b40SSuryakanth Sekar static uint8_t executeCmd(const char* path)
1156822b0b40SSuryakanth Sekar {
1157822b0b40SSuryakanth Sekar     boost::process::child execProg(path);
1158822b0b40SSuryakanth Sekar     execProg.wait();
1159822b0b40SSuryakanth Sekar 
1160822b0b40SSuryakanth Sekar     int retCode = execProg.exit_code();
1161822b0b40SSuryakanth Sekar     if (retCode)
1162822b0b40SSuryakanth Sekar     {
1163822b0b40SSuryakanth Sekar         return ipmi::ccUnspecifiedError;
1164822b0b40SSuryakanth Sekar     }
1165822b0b40SSuryakanth Sekar     return ipmi::ccSuccess;
1166822b0b40SSuryakanth Sekar }
1167822b0b40SSuryakanth Sekar 
1168822b0b40SSuryakanth Sekar /** @brief implementes ASD Security event logging
1169822b0b40SSuryakanth Sekar  *  @param[in] Event message string
1170822b0b40SSuryakanth Sekar  *  @param[in] Event Severity
1171822b0b40SSuryakanth Sekar  *  @returns status
1172822b0b40SSuryakanth Sekar  */
1173822b0b40SSuryakanth Sekar 
1174822b0b40SSuryakanth Sekar static void atScaleDebugEventlog(std::string msg, int severity)
1175822b0b40SSuryakanth Sekar {
1176822b0b40SSuryakanth Sekar     std::string eventStr = "OpenBMC.0.1." + msg;
1177822b0b40SSuryakanth Sekar     sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1178822b0b40SSuryakanth Sekar                     "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1179822b0b40SSuryakanth Sekar                     eventStr.c_str(), NULL);
1180822b0b40SSuryakanth Sekar }
1181822b0b40SSuryakanth Sekar 
1182fc5e985bSRichard Marian Thomaiyar /** @brief implementes setting password for special user
1183fc5e985bSRichard Marian Thomaiyar  *  @param[in] specialUserIndex
1184fc5e985bSRichard Marian Thomaiyar  *  @param[in] userPassword - new password in 20 bytes
1185fc5e985bSRichard Marian Thomaiyar  *  @returns ipmi completion code.
1186fc5e985bSRichard Marian Thomaiyar  */
1187fc5e985bSRichard Marian Thomaiyar ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1188fc5e985bSRichard Marian Thomaiyar                                               uint8_t specialUserIndex,
1189fc5e985bSRichard Marian Thomaiyar                                               std::vector<uint8_t> userPassword)
1190fc5e985bSRichard Marian Thomaiyar {
1191fc5e985bSRichard Marian Thomaiyar     ChannelInfo chInfo;
1192822b0b40SSuryakanth Sekar     ipmi_ret_t status = ipmi::ccSuccess;
1193822b0b40SSuryakanth Sekar 
1194fc5e985bSRichard Marian Thomaiyar     try
1195fc5e985bSRichard Marian Thomaiyar     {
1196fc5e985bSRichard Marian Thomaiyar         getChannelInfo(ctx->channel, chInfo);
1197fc5e985bSRichard Marian Thomaiyar     }
1198fc5e985bSRichard Marian Thomaiyar     catch (sdbusplus::exception_t& e)
1199fc5e985bSRichard Marian Thomaiyar     {
1200fc5e985bSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
1201fc5e985bSRichard Marian Thomaiyar             "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1202fc5e985bSRichard Marian Thomaiyar             phosphor::logging::entry("MSG: %s", e.description()));
1203fc5e985bSRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
1204fc5e985bSRichard Marian Thomaiyar     }
1205fc5e985bSRichard Marian Thomaiyar     if (chInfo.mediumType !=
1206fc5e985bSRichard Marian Thomaiyar         static_cast<uint8_t>(EChannelMediumType::systemInterface))
1207fc5e985bSRichard Marian Thomaiyar     {
1208fc5e985bSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
1209fc5e985bSRichard Marian Thomaiyar             "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1210fc5e985bSRichard Marian Thomaiyar             "interface");
1211fc5e985bSRichard Marian Thomaiyar         return ipmi::responseCommandNotAvailable();
1212fc5e985bSRichard Marian Thomaiyar     }
1213822b0b40SSuryakanth Sekar 
1214822b0b40SSuryakanth Sekar     // 0 for root user  and 1 for AtScaleDebug is allowed
1215822b0b40SSuryakanth Sekar     if (specialUserIndex >
1216822b0b40SSuryakanth Sekar         static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1217fc5e985bSRichard Marian Thomaiyar     {
1218fc5e985bSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
1219fc5e985bSRichard Marian Thomaiyar             "ipmiOEMSetSpecialUserPassword: Invalid user account");
1220fc5e985bSRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
1221fc5e985bSRichard Marian Thomaiyar     }
1222822b0b40SSuryakanth Sekar     if (userPassword.size() != 0)
1223822b0b40SSuryakanth Sekar     {
1224fc5e985bSRichard Marian Thomaiyar         constexpr uint8_t minPasswordSizeRequired = 6;
1225822b0b40SSuryakanth Sekar         std::string passwd;
1226fc5e985bSRichard Marian Thomaiyar         if (userPassword.size() < minPasswordSizeRequired ||
1227fc5e985bSRichard Marian Thomaiyar             userPassword.size() > ipmi::maxIpmi20PasswordSize)
1228fc5e985bSRichard Marian Thomaiyar         {
12299420416aSJayaprakash Mutyala             OPENSSL_cleanse(userPassword.data(), userPassword.size());
1230fc5e985bSRichard Marian Thomaiyar             return ipmi::responseReqDataLenInvalid();
1231fc5e985bSRichard Marian Thomaiyar         }
1232fc5e985bSRichard Marian Thomaiyar         passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1233fc5e985bSRichard Marian Thomaiyar                       userPassword.size());
12349420416aSJayaprakash Mutyala         // Clear sensitive data
12359420416aSJayaprakash Mutyala         OPENSSL_cleanse(userPassword.data(), userPassword.size());
1236822b0b40SSuryakanth Sekar         if (specialUserIndex ==
1237822b0b40SSuryakanth Sekar             static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1238822b0b40SSuryakanth Sekar         {
1239822b0b40SSuryakanth Sekar             status = ipmiSetSpecialUserPassword("asdbg", passwd);
1240822b0b40SSuryakanth Sekar 
1241822b0b40SSuryakanth Sekar             atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1242822b0b40SSuryakanth Sekar         }
1243822b0b40SSuryakanth Sekar         else
1244822b0b40SSuryakanth Sekar         {
1245822b0b40SSuryakanth Sekar             status = ipmiSetSpecialUserPassword("root", passwd);
1246822b0b40SSuryakanth Sekar         }
12479420416aSJayaprakash Mutyala         // Clear sensitive data
12489420416aSJayaprakash Mutyala         OPENSSL_cleanse(&passwd, passwd.length());
12499420416aSJayaprakash Mutyala 
1250822b0b40SSuryakanth Sekar         return ipmi::response(status);
1251822b0b40SSuryakanth Sekar     }
1252822b0b40SSuryakanth Sekar     else
1253822b0b40SSuryakanth Sekar     {
1254822b0b40SSuryakanth Sekar         if (specialUserIndex ==
1255822b0b40SSuryakanth Sekar             static_cast<uint8_t>(SpecialUserIndex::rootUser))
1256822b0b40SSuryakanth Sekar         {
1257822b0b40SSuryakanth Sekar             status = executeCmd("passwd -d root");
1258822b0b40SSuryakanth Sekar         }
1259822b0b40SSuryakanth Sekar         else
1260822b0b40SSuryakanth Sekar         {
1261822b0b40SSuryakanth Sekar 
1262822b0b40SSuryakanth Sekar             status = executeCmd("passwd -d asdbg");
1263822b0b40SSuryakanth Sekar 
1264822b0b40SSuryakanth Sekar             if (status == 0)
1265822b0b40SSuryakanth Sekar             {
1266822b0b40SSuryakanth Sekar                 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1267822b0b40SSuryakanth Sekar                                      LOG_INFO);
1268822b0b40SSuryakanth Sekar             }
1269822b0b40SSuryakanth Sekar         }
1270822b0b40SSuryakanth Sekar         return ipmi::response(status);
1271822b0b40SSuryakanth Sekar     }
1272fc5e985bSRichard Marian Thomaiyar }
1273fc5e985bSRichard Marian Thomaiyar 
127445f04988SKuiying Wang namespace ledAction
127545f04988SKuiying Wang {
127645f04988SKuiying Wang using namespace sdbusplus::xyz::openbmc_project::Led::server;
127745f04988SKuiying Wang std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
1278934ee9c9Sjayaprakash Mutyala     {Physical::Action::Off, 0},
1279934ee9c9Sjayaprakash Mutyala     {Physical::Action::On, 2},
1280934ee9c9Sjayaprakash Mutyala     {Physical::Action::Blink, 1}};
128145f04988SKuiying Wang 
128245f04988SKuiying Wang std::map<uint8_t, std::string> offsetObjPath = {
128345f04988SKuiying Wang     {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
128445f04988SKuiying Wang 
128545f04988SKuiying Wang } // namespace ledAction
128645f04988SKuiying Wang 
128745f04988SKuiying Wang int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
128845f04988SKuiying Wang                    const std::string& objPath, uint8_t& state)
128945f04988SKuiying Wang {
129045f04988SKuiying Wang     try
129145f04988SKuiying Wang     {
129245f04988SKuiying Wang         std::string service = getService(bus, intf, objPath);
129345f04988SKuiying Wang         Value stateValue =
129445f04988SKuiying Wang             getDbusProperty(bus, service, objPath, intf, "State");
12958166c8d7SVernon Mauery         std::string strState = std::get<std::string>(stateValue);
129645f04988SKuiying Wang         state = ledAction::actionDbusToIpmi.at(
129745f04988SKuiying Wang             sdbusplus::xyz::openbmc_project::Led::server::Physical::
129845f04988SKuiying Wang                 convertActionFromString(strState));
129945f04988SKuiying Wang     }
130045f04988SKuiying Wang     catch (sdbusplus::exception::SdBusError& e)
130145f04988SKuiying Wang     {
130245f04988SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
130345f04988SKuiying Wang         return -1;
130445f04988SKuiying Wang     }
130545f04988SKuiying Wang     return 0;
130645f04988SKuiying Wang }
130745f04988SKuiying Wang 
1308abd11ca3SNITIN SHARMA ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
130945f04988SKuiying Wang {
1310abd11ca3SNITIN SHARMA     uint8_t ledstate = 0;
131145f04988SKuiying Wang     phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
131215419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
131345f04988SKuiying Wang     for (auto it = ledAction::offsetObjPath.begin();
131445f04988SKuiying Wang          it != ledAction::offsetObjPath.end(); ++it)
131545f04988SKuiying Wang     {
131645f04988SKuiying Wang         uint8_t state = 0;
1317abd11ca3SNITIN SHARMA         if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
131845f04988SKuiying Wang         {
131945f04988SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
132045f04988SKuiying Wang                 "oem_get_led_status: fail to get ID LED status!");
1321abd11ca3SNITIN SHARMA             return ipmi::responseUnspecifiedError();
132245f04988SKuiying Wang         }
1323abd11ca3SNITIN SHARMA         ledstate |= state << it->first;
132445f04988SKuiying Wang     }
1325abd11ca3SNITIN SHARMA     return ipmi::responseSuccess(ledstate);
132645f04988SKuiying Wang }
132745f04988SKuiying Wang 
132823737fe3SYong Li ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
132923737fe3SYong Li                                          ipmi_request_t request,
133023737fe3SYong Li                                          ipmi_response_t response,
133123737fe3SYong Li                                          ipmi_data_len_t dataLen,
133223737fe3SYong Li                                          ipmi_context_t context)
133323737fe3SYong Li {
133423737fe3SYong Li     CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
133523737fe3SYong Li     uint8_t* resp = reinterpret_cast<uint8_t*>(response);
133623737fe3SYong Li 
133723737fe3SYong Li     if (*dataLen == 0)
133823737fe3SYong Li     {
133923737fe3SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
134023737fe3SYong Li             "CfgHostSerial: invalid input len!",
134123737fe3SYong Li             phosphor::logging::entry("LEN=%d", *dataLen));
134223737fe3SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
134323737fe3SYong Li     }
134423737fe3SYong Li 
134523737fe3SYong Li     switch (req->command)
134623737fe3SYong Li     {
134723737fe3SYong Li         case getHostSerialCfgCmd:
134823737fe3SYong Li         {
134923737fe3SYong Li             if (*dataLen != 1)
135023737fe3SYong Li             {
135123737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
135223737fe3SYong Li                     "CfgHostSerial: invalid input len!");
135323737fe3SYong Li                 *dataLen = 0;
135423737fe3SYong Li                 return IPMI_CC_REQ_DATA_LEN_INVALID;
135523737fe3SYong Li             }
135623737fe3SYong Li 
135723737fe3SYong Li             *dataLen = 0;
135823737fe3SYong Li 
135923737fe3SYong Li             boost::process::ipstream is;
136023737fe3SYong Li             std::vector<std::string> data;
136123737fe3SYong Li             std::string line;
136223737fe3SYong Li             boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
136323737fe3SYong Li                                      boost::process::std_out > is);
136423737fe3SYong Li 
136523737fe3SYong Li             while (c1.running() && std::getline(is, line) && !line.empty())
136623737fe3SYong Li             {
136723737fe3SYong Li                 data.push_back(line);
136823737fe3SYong Li             }
136923737fe3SYong Li 
137023737fe3SYong Li             c1.wait();
137123737fe3SYong Li             if (c1.exit_code())
137223737fe3SYong Li             {
137323737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
137423737fe3SYong Li                     "CfgHostSerial:: error on execute",
137523737fe3SYong Li                     phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
137623737fe3SYong Li                 // Using the default value
137723737fe3SYong Li                 *resp = 0;
137823737fe3SYong Li             }
137923737fe3SYong Li             else
138023737fe3SYong Li             {
138123737fe3SYong Li                 if (data.size() != 1)
138223737fe3SYong Li                 {
138323737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
138423737fe3SYong Li                         "CfgHostSerial:: error on read env");
138523737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
138623737fe3SYong Li                 }
138723737fe3SYong Li                 try
138823737fe3SYong Li                 {
138923737fe3SYong Li                     unsigned long tmp = std::stoul(data[0]);
139023737fe3SYong Li                     if (tmp > std::numeric_limits<uint8_t>::max())
139123737fe3SYong Li                     {
139223737fe3SYong Li                         throw std::out_of_range("Out of range");
139323737fe3SYong Li                     }
139423737fe3SYong Li                     *resp = static_cast<uint8_t>(tmp);
139523737fe3SYong Li                 }
139623737fe3SYong Li                 catch (const std::invalid_argument& e)
139723737fe3SYong Li                 {
139823737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
139923737fe3SYong Li                         "invalid config ",
140023737fe3SYong Li                         phosphor::logging::entry("ERR=%s", e.what()));
140123737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
140223737fe3SYong Li                 }
140323737fe3SYong Li                 catch (const std::out_of_range& e)
140423737fe3SYong Li                 {
140523737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
140623737fe3SYong Li                         "out_of_range config ",
140723737fe3SYong Li                         phosphor::logging::entry("ERR=%s", e.what()));
140823737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
140923737fe3SYong Li                 }
141023737fe3SYong Li             }
141123737fe3SYong Li 
141223737fe3SYong Li             *dataLen = 1;
141323737fe3SYong Li             break;
141423737fe3SYong Li         }
141523737fe3SYong Li         case setHostSerialCfgCmd:
141623737fe3SYong Li         {
141723737fe3SYong Li             if (*dataLen != sizeof(CfgHostSerialReq))
141823737fe3SYong Li             {
141923737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
142023737fe3SYong Li                     "CfgHostSerial: invalid input len!");
142123737fe3SYong Li                 *dataLen = 0;
142223737fe3SYong Li                 return IPMI_CC_REQ_DATA_LEN_INVALID;
142323737fe3SYong Li             }
142423737fe3SYong Li 
142523737fe3SYong Li             *dataLen = 0;
142623737fe3SYong Li 
142723737fe3SYong Li             if (req->parameter > HostSerialCfgParamMax)
142823737fe3SYong Li             {
142923737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
143023737fe3SYong Li                     "CfgHostSerial: invalid input!");
143123737fe3SYong Li                 return IPMI_CC_INVALID_FIELD_REQUEST;
143223737fe3SYong Li             }
143323737fe3SYong Li 
143423737fe3SYong Li             boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
143523737fe3SYong Li                                      std::to_string(req->parameter));
143623737fe3SYong Li 
143723737fe3SYong Li             c1.wait();
143823737fe3SYong Li             if (c1.exit_code())
143923737fe3SYong Li             {
144023737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
144123737fe3SYong Li                     "CfgHostSerial:: error on execute",
144223737fe3SYong Li                     phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
144323737fe3SYong Li                 return IPMI_CC_UNSPECIFIED_ERROR;
144423737fe3SYong Li             }
144523737fe3SYong Li             break;
144623737fe3SYong Li         }
144723737fe3SYong Li         default:
144823737fe3SYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
144923737fe3SYong Li                 "CfgHostSerial: invalid input!");
145023737fe3SYong Li             *dataLen = 0;
145123737fe3SYong Li             return IPMI_CC_INVALID_FIELD_REQUEST;
145223737fe3SYong Li     }
145323737fe3SYong Li 
145423737fe3SYong Li     return IPMI_CC_OK;
145523737fe3SYong Li }
145623737fe3SYong Li 
145791244a6aSJames Feist constexpr const char* thermalModeInterface =
145891244a6aSJames Feist     "xyz.openbmc_project.Control.ThermalMode";
145991244a6aSJames Feist constexpr const char* thermalModePath =
146091244a6aSJames Feist     "/xyz/openbmc_project/control/thermal_mode";
146191244a6aSJames Feist 
146291244a6aSJames Feist bool getFanProfileInterface(
146391244a6aSJames Feist     sdbusplus::bus::bus& bus,
146491244a6aSJames Feist     boost::container::flat_map<
146591244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>& resp)
146691244a6aSJames Feist {
146791244a6aSJames Feist     auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
146891244a6aSJames Feist                                     "GetAll");
146991244a6aSJames Feist     call.append(thermalModeInterface);
147091244a6aSJames Feist     try
147191244a6aSJames Feist     {
147291244a6aSJames Feist         auto data = bus.call(call);
147391244a6aSJames Feist         data.read(resp);
147491244a6aSJames Feist     }
147591244a6aSJames Feist     catch (sdbusplus::exception_t& e)
147691244a6aSJames Feist     {
147791244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
147891244a6aSJames Feist             "getFanProfileInterface: can't get thermal mode!",
147991244a6aSJames Feist             phosphor::logging::entry("ERR=%s", e.what()));
148091244a6aSJames Feist         return false;
148191244a6aSJames Feist     }
148291244a6aSJames Feist     return true;
148391244a6aSJames Feist }
148491244a6aSJames Feist 
1485f945eee0Sanil kumar appana /**@brief implements the OEM set fan config.
1486f945eee0Sanil kumar appana  * @param selectedFanProfile - fan profile to enable
1487f945eee0Sanil kumar appana  * @param reserved1
1488f945eee0Sanil kumar appana  * @param performanceMode - Performance/Acoustic mode
1489f945eee0Sanil kumar appana  * @param reserved2
1490f945eee0Sanil kumar appana  * @param setPerformanceMode - set Performance/Acoustic mode
1491f945eee0Sanil kumar appana  * @param setFanProfile - set fan profile
1492f945eee0Sanil kumar appana  *
1493f945eee0Sanil kumar appana  * @return IPMI completion code.
1494f945eee0Sanil kumar appana  **/
1495f945eee0Sanil kumar appana ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
149691244a6aSJames Feist 
1497f945eee0Sanil kumar appana                                     uint2_t reserved1, bool performanceMode,
1498f945eee0Sanil kumar appana                                     uint3_t reserved2, bool setPerformanceMode,
1499619186dbSJoshi-Mansi                                     bool setFanProfile,
1500619186dbSJoshi-Mansi                                     std::optional<uint8_t> dimmGroupId,
1501619186dbSJoshi-Mansi                                     std::optional<uint32_t> dimmPresenceBitmap)
150291244a6aSJames Feist {
1503f945eee0Sanil kumar appana     if (reserved1 || reserved2)
1504f945eee0Sanil kumar appana     {
1505f945eee0Sanil kumar appana         return ipmi::responseInvalidFieldRequest();
150691244a6aSJames Feist     }
1507619186dbSJoshi-Mansi 
1508619186dbSJoshi-Mansi     if (dimmGroupId)
1509619186dbSJoshi-Mansi     {
1510619186dbSJoshi-Mansi         if (*dimmGroupId >= maxCPUNum)
1511619186dbSJoshi-Mansi         {
1512619186dbSJoshi-Mansi             return ipmi::responseInvalidFieldRequest();
1513619186dbSJoshi-Mansi         }
1514619186dbSJoshi-Mansi         if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1515619186dbSJoshi-Mansi         {
1516619186dbSJoshi-Mansi             return ipmi::responseInvalidFieldRequest();
1517619186dbSJoshi-Mansi         }
1518619186dbSJoshi-Mansi     }
1519619186dbSJoshi-Mansi 
152091244a6aSJames Feist     // todo: tell bios to only send first 2 bytes
152191244a6aSJames Feist     boost::container::flat_map<
152291244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>
152391244a6aSJames Feist         profileData;
152415419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
152515419dd5SVernon Mauery     if (!getFanProfileInterface(*dbus, profileData))
152691244a6aSJames Feist     {
1527f945eee0Sanil kumar appana         return ipmi::responseUnspecifiedError();
152891244a6aSJames Feist     }
152991244a6aSJames Feist 
153091244a6aSJames Feist     std::vector<std::string>* supported =
153191244a6aSJames Feist         std::get_if<std::vector<std::string>>(&profileData["Supported"]);
153291244a6aSJames Feist     if (supported == nullptr)
153391244a6aSJames Feist     {
1534f945eee0Sanil kumar appana         return ipmi::responseInvalidFieldRequest();
153591244a6aSJames Feist     }
153691244a6aSJames Feist     std::string mode;
1537f945eee0Sanil kumar appana     if (setPerformanceMode)
153891244a6aSJames Feist     {
153991244a6aSJames Feist         if (performanceMode)
154091244a6aSJames Feist         {
154191244a6aSJames Feist 
154291244a6aSJames Feist             if (std::find(supported->begin(), supported->end(),
154391244a6aSJames Feist                           "Performance") != supported->end())
154491244a6aSJames Feist             {
154591244a6aSJames Feist                 mode = "Performance";
154691244a6aSJames Feist             }
154791244a6aSJames Feist         }
154891244a6aSJames Feist         else
154991244a6aSJames Feist         {
155091244a6aSJames Feist             if (std::find(supported->begin(), supported->end(), "Acoustic") !=
155191244a6aSJames Feist                 supported->end())
155291244a6aSJames Feist             {
155391244a6aSJames Feist                 mode = "Acoustic";
155491244a6aSJames Feist             }
155591244a6aSJames Feist         }
155691244a6aSJames Feist         if (mode.empty())
155791244a6aSJames Feist         {
1558f945eee0Sanil kumar appana             return ipmi::responseInvalidFieldRequest();
155991244a6aSJames Feist         }
1560f945eee0Sanil kumar appana 
1561f945eee0Sanil kumar appana         try
1562f945eee0Sanil kumar appana         {
156315419dd5SVernon Mauery             setDbusProperty(*dbus, settingsBusName, thermalModePath,
156491244a6aSJames Feist                             thermalModeInterface, "Current", mode);
156591244a6aSJames Feist         }
1566f945eee0Sanil kumar appana         catch (sdbusplus::exception_t& e)
1567f945eee0Sanil kumar appana         {
1568f945eee0Sanil kumar appana             phosphor::logging::log<phosphor::logging::level::ERR>(
1569f945eee0Sanil kumar appana                 "ipmiOEMSetFanConfig: can't set thermal mode!",
1570f945eee0Sanil kumar appana                 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1571f945eee0Sanil kumar appana             return ipmi::responseResponseError();
1572f945eee0Sanil kumar appana         }
1573f945eee0Sanil kumar appana     }
157491244a6aSJames Feist 
1575f945eee0Sanil kumar appana     return ipmi::responseSuccess();
157691244a6aSJames Feist }
157791244a6aSJames Feist 
15785b693637SJames Feist ipmi::RspType<uint8_t, // profile support map
15795b693637SJames Feist               uint8_t, // fan control profile enable
15805b693637SJames Feist               uint8_t, // flags
15815b693637SJames Feist               uint32_t // dimm presence bit map
15825b693637SJames Feist               >
15835b693637SJames Feist     ipmiOEMGetFanConfig(uint8_t dimmGroupId)
158491244a6aSJames Feist {
158536f05ce6SJoshi-Mansi     if (dimmGroupId >= maxCPUNum)
158636f05ce6SJoshi-Mansi     {
158736f05ce6SJoshi-Mansi         return ipmi::responseInvalidFieldRequest();
158836f05ce6SJoshi-Mansi     }
158936f05ce6SJoshi-Mansi 
159036f05ce6SJoshi-Mansi     bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
159136f05ce6SJoshi-Mansi 
159236f05ce6SJoshi-Mansi     if (!cpuStatus)
159336f05ce6SJoshi-Mansi     {
159436f05ce6SJoshi-Mansi         return ipmi::responseInvalidFieldRequest();
159536f05ce6SJoshi-Mansi     }
159636f05ce6SJoshi-Mansi 
159791244a6aSJames Feist     boost::container::flat_map<
159891244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>
159991244a6aSJames Feist         profileData;
160091244a6aSJames Feist 
160115419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
160215419dd5SVernon Mauery     if (!getFanProfileInterface(*dbus, profileData))
160391244a6aSJames Feist     {
16045b693637SJames Feist         return ipmi::responseResponseError();
160591244a6aSJames Feist     }
160691244a6aSJames Feist 
160791244a6aSJames Feist     std::string* current = std::get_if<std::string>(&profileData["Current"]);
160891244a6aSJames Feist 
160991244a6aSJames Feist     if (current == nullptr)
161091244a6aSJames Feist     {
161191244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
161291244a6aSJames Feist             "ipmiOEMGetFanConfig: can't get current mode!");
16135b693637SJames Feist         return ipmi::responseResponseError();
161491244a6aSJames Feist     }
161591244a6aSJames Feist     bool performance = (*current == "Performance");
161691244a6aSJames Feist 
16175b693637SJames Feist     uint8_t flags = 0;
161891244a6aSJames Feist     if (performance)
161991244a6aSJames Feist     {
16205b693637SJames Feist         flags |= 1 << 2;
162191244a6aSJames Feist     }
162291244a6aSJames Feist 
16234b1552d8Sjayaprakash Mutyala     constexpr uint8_t fanControlDefaultProfile = 0x80;
16244b1552d8Sjayaprakash Mutyala     constexpr uint8_t fanControlProfileState = 0x00;
16254b1552d8Sjayaprakash Mutyala     constexpr uint32_t dimmPresenceBitmap = 0x00;
16264b1552d8Sjayaprakash Mutyala 
16274b1552d8Sjayaprakash Mutyala     return ipmi::responseSuccess(fanControlDefaultProfile,
16284b1552d8Sjayaprakash Mutyala                                  fanControlProfileState, flags,
16294b1552d8Sjayaprakash Mutyala                                  dimmPresenceBitmap);
163091244a6aSJames Feist }
16315f957cafSJames Feist constexpr const char* cfmLimitSettingPath =
16325f957cafSJames Feist     "/xyz/openbmc_project/control/cfm_limit";
16335f957cafSJames Feist constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
1634faa4f223SJames Feist constexpr const size_t legacyExitAirSensorNumber = 0x2e;
163509f6b604SJames Feist constexpr const size_t legacyPCHSensorNumber = 0x22;
163609f6b604SJames Feist constexpr const char* exitAirPathName = "Exit_Air";
163709f6b604SJames Feist constexpr const char* pchPathName = "SSB_Temp";
1638acc8a4ebSJames Feist constexpr const char* pidConfigurationIface =
1639acc8a4ebSJames Feist     "xyz.openbmc_project.Configuration.Pid";
1640faa4f223SJames Feist 
164109f6b604SJames Feist static std::string getConfigPath(const std::string& name)
1642faa4f223SJames Feist {
164315419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1644faa4f223SJames Feist     auto method =
164515419dd5SVernon Mauery         dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1646faa4f223SJames Feist                               "/xyz/openbmc_project/object_mapper",
1647faa4f223SJames Feist                               "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1648faa4f223SJames Feist 
1649acc8a4ebSJames Feist     method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1650faa4f223SJames Feist     std::string path;
1651faa4f223SJames Feist     GetSubTreeType resp;
1652faa4f223SJames Feist     try
1653faa4f223SJames Feist     {
165415419dd5SVernon Mauery         auto reply = dbus->call(method);
1655faa4f223SJames Feist         reply.read(resp);
1656faa4f223SJames Feist     }
1657faa4f223SJames Feist     catch (sdbusplus::exception_t&)
1658faa4f223SJames Feist     {
1659faa4f223SJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1660faa4f223SJames Feist             "ipmiOEMGetFscParameter: mapper error");
1661faa4f223SJames Feist     };
166209f6b604SJames Feist     auto config =
166309f6b604SJames Feist         std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
166409f6b604SJames Feist             return pair.first.find(name) != std::string::npos;
1665faa4f223SJames Feist         });
1666faa4f223SJames Feist     if (config != resp.end())
1667faa4f223SJames Feist     {
1668faa4f223SJames Feist         path = std::move(config->first);
1669faa4f223SJames Feist     }
1670faa4f223SJames Feist     return path;
1671faa4f223SJames Feist }
16725f957cafSJames Feist 
1673acc8a4ebSJames Feist // flat map to make alphabetical
1674acc8a4ebSJames Feist static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1675acc8a4ebSJames Feist {
1676acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> ret;
167715419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1678acc8a4ebSJames Feist     auto method =
167915419dd5SVernon Mauery         dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1680acc8a4ebSJames Feist                               "/xyz/openbmc_project/object_mapper",
1681acc8a4ebSJames Feist                               "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1682acc8a4ebSJames Feist 
1683acc8a4ebSJames Feist     method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1684acc8a4ebSJames Feist     GetSubTreeType resp;
1685acc8a4ebSJames Feist 
1686acc8a4ebSJames Feist     try
1687acc8a4ebSJames Feist     {
168815419dd5SVernon Mauery         auto reply = dbus->call(method);
1689acc8a4ebSJames Feist         reply.read(resp);
1690acc8a4ebSJames Feist     }
1691acc8a4ebSJames Feist     catch (sdbusplus::exception_t&)
1692acc8a4ebSJames Feist     {
1693acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1694acc8a4ebSJames Feist             "getFanConfigPaths: mapper error");
1695acc8a4ebSJames Feist     };
1696acc8a4ebSJames Feist     for (const auto& [path, objects] : resp)
1697acc8a4ebSJames Feist     {
1698acc8a4ebSJames Feist         if (objects.empty())
1699acc8a4ebSJames Feist         {
1700acc8a4ebSJames Feist             continue; // should be impossible
1701acc8a4ebSJames Feist         }
1702be560b09SZhu, Yunge 
1703be560b09SZhu, Yunge         try
1704be560b09SZhu, Yunge         {
170515419dd5SVernon Mauery             ret.emplace(path,
170615419dd5SVernon Mauery                         getAllDbusProperties(*dbus, objects[0].first, path,
1707acc8a4ebSJames Feist                                              pidConfigurationIface));
1708acc8a4ebSJames Feist         }
1709be560b09SZhu, Yunge         catch (sdbusplus::exception_t& e)
1710be560b09SZhu, Yunge         {
1711be560b09SZhu, Yunge             phosphor::logging::log<phosphor::logging::level::ERR>(
1712be560b09SZhu, Yunge                 "getPidConfigs: can't get DbusProperties!",
1713be560b09SZhu, Yunge                 phosphor::logging::entry("ERR=%s", e.what()));
1714be560b09SZhu, Yunge         }
1715be560b09SZhu, Yunge     }
1716acc8a4ebSJames Feist     return ret;
1717acc8a4ebSJames Feist }
1718acc8a4ebSJames Feist 
1719acc8a4ebSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1720acc8a4ebSJames Feist {
1721acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1722acc8a4ebSJames Feist     if (data.empty())
1723acc8a4ebSJames Feist     {
1724acc8a4ebSJames Feist         return ipmi::responseResponseError();
1725acc8a4ebSJames Feist     }
1726acc8a4ebSJames Feist     uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1727acc8a4ebSJames Feist     for (const auto& [_, pid] : data)
1728acc8a4ebSJames Feist     {
1729acc8a4ebSJames Feist         auto findClass = pid.find("Class");
1730acc8a4ebSJames Feist         if (findClass == pid.end())
1731acc8a4ebSJames Feist         {
1732acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1733acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: found illegal pid "
1734acc8a4ebSJames Feist                 "configurations");
1735acc8a4ebSJames Feist             return ipmi::responseResponseError();
1736acc8a4ebSJames Feist         }
1737acc8a4ebSJames Feist         std::string type = std::get<std::string>(findClass->second);
1738acc8a4ebSJames Feist         if (type == "fan")
1739acc8a4ebSJames Feist         {
1740acc8a4ebSJames Feist             auto findOutLimit = pid.find("OutLimitMin");
1741acc8a4ebSJames Feist             if (findOutLimit == pid.end())
1742acc8a4ebSJames Feist             {
1743acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1744acc8a4ebSJames Feist                     "ipmiOEMGetFscParameter: found illegal pid "
1745acc8a4ebSJames Feist                     "configurations");
1746acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1747acc8a4ebSJames Feist             }
1748acc8a4ebSJames Feist             // get the min out of all the offsets
1749acc8a4ebSJames Feist             minOffset = std::min(
1750acc8a4ebSJames Feist                 minOffset,
1751acc8a4ebSJames Feist                 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1752acc8a4ebSJames Feist         }
1753acc8a4ebSJames Feist     }
1754acc8a4ebSJames Feist     if (minOffset == std::numeric_limits<uint8_t>::max())
1755acc8a4ebSJames Feist     {
1756acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1757acc8a4ebSJames Feist             "ipmiOEMGetFscParameter: found no fan configurations!");
1758acc8a4ebSJames Feist         return ipmi::responseResponseError();
1759acc8a4ebSJames Feist     }
1760acc8a4ebSJames Feist 
1761acc8a4ebSJames Feist     return ipmi::responseSuccess(minOffset);
1762acc8a4ebSJames Feist }
1763acc8a4ebSJames Feist 
1764acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1765acc8a4ebSJames Feist {
1766acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1767acc8a4ebSJames Feist     if (data.empty())
1768acc8a4ebSJames Feist     {
1769acc8a4ebSJames Feist 
1770acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1771acc8a4ebSJames Feist             "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1772acc8a4ebSJames Feist         return ipmi::responseResponseError();
1773acc8a4ebSJames Feist     }
1774acc8a4ebSJames Feist 
177515419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1776acc8a4ebSJames Feist     bool found = false;
1777acc8a4ebSJames Feist     for (const auto& [path, pid] : data)
1778acc8a4ebSJames Feist     {
1779acc8a4ebSJames Feist         auto findClass = pid.find("Class");
1780acc8a4ebSJames Feist         if (findClass == pid.end())
1781acc8a4ebSJames Feist         {
1782acc8a4ebSJames Feist 
1783acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1784acc8a4ebSJames Feist                 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1785acc8a4ebSJames Feist                 "configurations");
1786acc8a4ebSJames Feist             return ipmi::responseResponseError();
1787acc8a4ebSJames Feist         }
1788acc8a4ebSJames Feist         std::string type = std::get<std::string>(findClass->second);
1789acc8a4ebSJames Feist         if (type == "fan")
1790acc8a4ebSJames Feist         {
1791acc8a4ebSJames Feist             auto findOutLimit = pid.find("OutLimitMin");
1792acc8a4ebSJames Feist             if (findOutLimit == pid.end())
1793acc8a4ebSJames Feist             {
1794acc8a4ebSJames Feist 
1795acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1796acc8a4ebSJames Feist                     "ipmiOEMSetFanSpeedOffset: found illegal pid "
1797acc8a4ebSJames Feist                     "configurations");
1798acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1799acc8a4ebSJames Feist             }
180015419dd5SVernon Mauery             ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
1801acc8a4ebSJames Feist                                   path, pidConfigurationIface, "OutLimitMin",
1802acc8a4ebSJames Feist                                   static_cast<double>(offset));
1803acc8a4ebSJames Feist             found = true;
1804acc8a4ebSJames Feist         }
1805acc8a4ebSJames Feist     }
1806acc8a4ebSJames Feist     if (!found)
1807acc8a4ebSJames Feist     {
1808acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1809acc8a4ebSJames Feist             "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1810acc8a4ebSJames Feist         return ipmi::responseResponseError();
1811acc8a4ebSJames Feist     }
1812acc8a4ebSJames Feist 
1813acc8a4ebSJames Feist     return ipmi::responseSuccess();
1814acc8a4ebSJames Feist }
1815acc8a4ebSJames Feist 
1816acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1817acc8a4ebSJames Feist                                        uint8_t param2)
18185f957cafSJames Feist {
18195f957cafSJames Feist     constexpr const size_t disableLimiting = 0x0;
18205f957cafSJames Feist 
182115419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1822acc8a4ebSJames Feist     if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
18235f957cafSJames Feist     {
182409f6b604SJames Feist         std::string pathName;
1825acc8a4ebSJames Feist         if (param1 == legacyExitAirSensorNumber)
1826faa4f223SJames Feist         {
182709f6b604SJames Feist             pathName = exitAirPathName;
182809f6b604SJames Feist         }
182909f6b604SJames Feist         else if (param1 == legacyPCHSensorNumber)
183009f6b604SJames Feist         {
183109f6b604SJames Feist             pathName = pchPathName;
1832faa4f223SJames Feist         }
1833faa4f223SJames Feist         else
1834faa4f223SJames Feist         {
1835acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
1836faa4f223SJames Feist         }
183709f6b604SJames Feist         std::string path = getConfigPath(pathName);
183809f6b604SJames Feist         ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
183909f6b604SJames Feist                               pidConfigurationIface, "SetPoint",
184009f6b604SJames Feist                               static_cast<double>(param2));
184109f6b604SJames Feist         return ipmi::responseSuccess();
1842faa4f223SJames Feist     }
1843acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
18445f957cafSJames Feist     {
1845acc8a4ebSJames Feist         uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
18465f957cafSJames Feist 
18475f957cafSJames Feist         // must be greater than 50 based on eps
18485f957cafSJames Feist         if (cfm < 50 && cfm != disableLimiting)
18495f957cafSJames Feist         {
1850acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
18515f957cafSJames Feist         }
18525f957cafSJames Feist 
18535f957cafSJames Feist         try
18545f957cafSJames Feist         {
185515419dd5SVernon Mauery             ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
18565f957cafSJames Feist                                   cfmLimitIface, "Limit",
18575f957cafSJames Feist                                   static_cast<double>(cfm));
18585f957cafSJames Feist         }
18595f957cafSJames Feist         catch (sdbusplus::exception_t& e)
18605f957cafSJames Feist         {
18615f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
18625f957cafSJames Feist                 "ipmiOEMSetFscParameter: can't set cfm setting!",
18635f957cafSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
1864acc8a4ebSJames Feist             return ipmi::responseResponseError();
18655f957cafSJames Feist         }
1866acc8a4ebSJames Feist         return ipmi::responseSuccess();
1867acc8a4ebSJames Feist     }
1868acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1869acc8a4ebSJames Feist     {
1870acc8a4ebSJames Feist         constexpr const size_t maxDomainCount = 8;
1871acc8a4ebSJames Feist         uint8_t requestedDomainMask = param1;
1872acc8a4ebSJames Feist         boost::container::flat_map data = getPidConfigs();
1873acc8a4ebSJames Feist         if (data.empty())
1874acc8a4ebSJames Feist         {
1875acc8a4ebSJames Feist 
1876acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1877acc8a4ebSJames Feist                 "ipmiOEMSetFscParameter: found no pid configurations!");
1878acc8a4ebSJames Feist             return ipmi::responseResponseError();
1879acc8a4ebSJames Feist         }
1880acc8a4ebSJames Feist         size_t count = 0;
1881acc8a4ebSJames Feist         for (const auto& [path, pid] : data)
1882acc8a4ebSJames Feist         {
1883acc8a4ebSJames Feist             auto findClass = pid.find("Class");
1884acc8a4ebSJames Feist             if (findClass == pid.end())
1885acc8a4ebSJames Feist             {
1886acc8a4ebSJames Feist 
1887acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1888acc8a4ebSJames Feist                     "ipmiOEMSetFscParameter: found illegal pid "
1889acc8a4ebSJames Feist                     "configurations");
1890acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1891acc8a4ebSJames Feist             }
1892acc8a4ebSJames Feist             std::string type = std::get<std::string>(findClass->second);
1893acc8a4ebSJames Feist             if (type == "fan")
1894acc8a4ebSJames Feist             {
1895acc8a4ebSJames Feist                 if (requestedDomainMask & (1 << count))
1896acc8a4ebSJames Feist                 {
1897acc8a4ebSJames Feist                     ipmi::setDbusProperty(
189815419dd5SVernon Mauery                         *dbus, "xyz.openbmc_project.EntityManager", path,
1899acc8a4ebSJames Feist                         pidConfigurationIface, "OutLimitMax",
1900acc8a4ebSJames Feist                         static_cast<double>(param2));
1901acc8a4ebSJames Feist                 }
1902acc8a4ebSJames Feist                 count++;
1903acc8a4ebSJames Feist             }
1904acc8a4ebSJames Feist         }
1905acc8a4ebSJames Feist         return ipmi::responseSuccess();
19065f957cafSJames Feist     }
19075f957cafSJames Feist     else
19085f957cafSJames Feist     {
19095f957cafSJames Feist         // todo other command parts possibly
19105f957cafSJames Feist         // tcontrol is handled in peci now
19115f957cafSJames Feist         // fan speed offset not implemented yet
19125f957cafSJames Feist         // domain pwm limit not implemented
1913acc8a4ebSJames Feist         return ipmi::responseParmOutOfRange();
19145f957cafSJames Feist     }
19155f957cafSJames Feist }
19165f957cafSJames Feist 
1917acc8a4ebSJames Feist ipmi::RspType<
1918acc8a4ebSJames Feist     std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1919acc8a4ebSJames Feist     ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
19205f957cafSJames Feist {
192109f6b604SJames Feist     constexpr uint8_t legacyDefaultSetpoint = -128;
19225f957cafSJames Feist 
192315419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1924acc8a4ebSJames Feist     if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
19255f957cafSJames Feist     {
1926acc8a4ebSJames Feist         if (!param)
1927acc8a4ebSJames Feist         {
1928acc8a4ebSJames Feist             return ipmi::responseReqDataLenInvalid();
19295f957cafSJames Feist         }
19305f957cafSJames Feist 
193109f6b604SJames Feist         std::string pathName;
193209f6b604SJames Feist 
193309f6b604SJames Feist         if (*param == legacyExitAirSensorNumber)
193409f6b604SJames Feist         {
193509f6b604SJames Feist             pathName = exitAirPathName;
193609f6b604SJames Feist         }
193709f6b604SJames Feist         else if (*param == legacyPCHSensorNumber)
193809f6b604SJames Feist         {
193909f6b604SJames Feist             pathName = pchPathName;
194009f6b604SJames Feist         }
194109f6b604SJames Feist         else
1942faa4f223SJames Feist         {
1943acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
1944faa4f223SJames Feist         }
194509f6b604SJames Feist 
194609f6b604SJames Feist         uint8_t setpoint = legacyDefaultSetpoint;
194709f6b604SJames Feist         std::string path = getConfigPath(pathName);
1948faa4f223SJames Feist         if (path.size())
1949faa4f223SJames Feist         {
195015419dd5SVernon Mauery             Value val = ipmi::getDbusProperty(
195115419dd5SVernon Mauery                 *dbus, "xyz.openbmc_project.EntityManager", path,
195215419dd5SVernon Mauery                 pidConfigurationIface, "SetPoint");
1953faa4f223SJames Feist             setpoint = std::floor(std::get<double>(val) + 0.5);
1954faa4f223SJames Feist         }
1955faa4f223SJames Feist 
1956faa4f223SJames Feist         // old implementation used to return the "default" and current, we
1957faa4f223SJames Feist         // don't make the default readily available so just make both the
1958faa4f223SJames Feist         // same
1959faa4f223SJames Feist 
1960acc8a4ebSJames Feist         return ipmi::responseSuccess(
1961acc8a4ebSJames Feist             std::array<uint8_t, 2>{setpoint, setpoint});
1962faa4f223SJames Feist     }
1963acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1964acc8a4ebSJames Feist     {
1965acc8a4ebSJames Feist         constexpr const size_t maxDomainCount = 8;
1966acc8a4ebSJames Feist 
1967acc8a4ebSJames Feist         if (!param)
1968acc8a4ebSJames Feist         {
1969acc8a4ebSJames Feist             return ipmi::responseReqDataLenInvalid();
1970acc8a4ebSJames Feist         }
1971acc8a4ebSJames Feist         uint8_t requestedDomain = *param;
1972acc8a4ebSJames Feist         if (requestedDomain >= maxDomainCount)
1973acc8a4ebSJames Feist         {
1974acc8a4ebSJames Feist             return ipmi::responseInvalidFieldRequest();
1975acc8a4ebSJames Feist         }
1976acc8a4ebSJames Feist 
1977acc8a4ebSJames Feist         boost::container::flat_map data = getPidConfigs();
1978acc8a4ebSJames Feist         if (data.empty())
1979acc8a4ebSJames Feist         {
1980acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1981acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: found no pid configurations!");
1982acc8a4ebSJames Feist             return ipmi::responseResponseError();
1983acc8a4ebSJames Feist         }
1984acc8a4ebSJames Feist         size_t count = 0;
1985acc8a4ebSJames Feist         for (const auto& [_, pid] : data)
1986acc8a4ebSJames Feist         {
1987acc8a4ebSJames Feist             auto findClass = pid.find("Class");
1988acc8a4ebSJames Feist             if (findClass == pid.end())
1989acc8a4ebSJames Feist             {
1990acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1991acc8a4ebSJames Feist                     "ipmiOEMGetFscParameter: found illegal pid "
1992acc8a4ebSJames Feist                     "configurations");
1993acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1994acc8a4ebSJames Feist             }
1995acc8a4ebSJames Feist             std::string type = std::get<std::string>(findClass->second);
1996acc8a4ebSJames Feist             if (type == "fan")
1997acc8a4ebSJames Feist             {
1998acc8a4ebSJames Feist                 if (requestedDomain == count)
1999acc8a4ebSJames Feist                 {
2000acc8a4ebSJames Feist                     auto findOutLimit = pid.find("OutLimitMax");
2001acc8a4ebSJames Feist                     if (findOutLimit == pid.end())
2002acc8a4ebSJames Feist                     {
2003acc8a4ebSJames Feist                         phosphor::logging::log<phosphor::logging::level::ERR>(
2004acc8a4ebSJames Feist                             "ipmiOEMGetFscParameter: found illegal pid "
2005acc8a4ebSJames Feist                             "configurations");
2006acc8a4ebSJames Feist                         return ipmi::responseResponseError();
2007acc8a4ebSJames Feist                     }
2008acc8a4ebSJames Feist 
2009acc8a4ebSJames Feist                     return ipmi::responseSuccess(
2010acc8a4ebSJames Feist                         static_cast<uint8_t>(std::floor(
2011acc8a4ebSJames Feist                             std::get<double>(findOutLimit->second) + 0.5)));
2012acc8a4ebSJames Feist                 }
2013acc8a4ebSJames Feist                 else
2014acc8a4ebSJames Feist                 {
2015acc8a4ebSJames Feist                     count++;
2016acc8a4ebSJames Feist                 }
2017acc8a4ebSJames Feist             }
2018acc8a4ebSJames Feist         }
2019acc8a4ebSJames Feist 
2020acc8a4ebSJames Feist         return ipmi::responseInvalidFieldRequest();
2021acc8a4ebSJames Feist     }
2022acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
20235f957cafSJames Feist     {
20245f957cafSJames Feist 
20255f957cafSJames Feist         /*
20265f957cafSJames Feist         DataLen should be 1, but host is sending us an extra bit. As the
2027acc8a4ebSJames Feist         previous behavior didn't seem to prevent this, ignore the check for
2028acc8a4ebSJames Feist         now.
20295f957cafSJames Feist 
2030acc8a4ebSJames Feist         if (param)
20315f957cafSJames Feist         {
20325f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
20335f957cafSJames Feist                 "ipmiOEMGetFscParameter: invalid input len!");
20345f957cafSJames Feist             return IPMI_CC_REQ_DATA_LEN_INVALID;
20355f957cafSJames Feist         }
20365f957cafSJames Feist         */
20375f957cafSJames Feist         Value cfmLimit;
20385f957cafSJames Feist         Value cfmMaximum;
20395f957cafSJames Feist         try
20405f957cafSJames Feist         {
204115419dd5SVernon Mauery             cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
20425f957cafSJames Feist                                              cfmLimitSettingPath, cfmLimitIface,
20435f957cafSJames Feist                                              "Limit");
20445f957cafSJames Feist             cfmMaximum = ipmi::getDbusProperty(
204515419dd5SVernon Mauery                 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
20465f957cafSJames Feist                 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
20475f957cafSJames Feist         }
20485f957cafSJames Feist         catch (sdbusplus::exception_t& e)
20495f957cafSJames Feist         {
20505f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
2051acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: can't get cfm setting!",
20525f957cafSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
2053acc8a4ebSJames Feist             return ipmi::responseResponseError();
20545f957cafSJames Feist         }
20555f957cafSJames Feist 
2056acc8a4ebSJames Feist         double cfmMax = std::get<double>(cfmMaximum);
2057acc8a4ebSJames Feist         double cfmLim = std::get<double>(cfmLimit);
2058acc8a4ebSJames Feist 
2059acc8a4ebSJames Feist         cfmLim = std::floor(cfmLim + 0.5);
2060acc8a4ebSJames Feist         cfmMax = std::floor(cfmMax + 0.5);
2061acc8a4ebSJames Feist         uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2062acc8a4ebSJames Feist         uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
2063acc8a4ebSJames Feist 
2064acc8a4ebSJames Feist         return ipmi::responseSuccess(
2065acc8a4ebSJames Feist             std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
20665f957cafSJames Feist     }
20675f957cafSJames Feist 
20685f957cafSJames Feist     else
20695f957cafSJames Feist     {
20705f957cafSJames Feist         // todo other command parts possibly
20715f957cafSJames Feist         // domain pwm limit not implemented
2072acc8a4ebSJames Feist         return ipmi::responseParmOutOfRange();
20735f957cafSJames Feist     }
20745f957cafSJames Feist }
20755f957cafSJames Feist 
2076773703a5SCheng C Yang using crConfigVariant =
2077773703a5SCheng C Yang     std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2078773703a5SCheng C Yang 
2079773703a5SCheng C Yang int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2080773703a5SCheng C Yang                 const crConfigVariant& value,
2081773703a5SCheng C Yang                 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2082773703a5SCheng C Yang {
2083773703a5SCheng C Yang     boost::system::error_code ec;
2084773703a5SCheng C Yang     ctx->bus->yield_method_call<void>(
2085e45333a8SKuiying Wang         ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
2086773703a5SCheng C Yang         "/xyz/openbmc_project/control/power_supply_redundancy",
2087773703a5SCheng C Yang         "org.freedesktop.DBus.Properties", "Set",
2088773703a5SCheng C Yang         "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2089773703a5SCheng C Yang     if (ec)
2090773703a5SCheng C Yang     {
2091773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
2092773703a5SCheng C Yang             "Failed to set dbus property to cold redundancy");
2093773703a5SCheng C Yang         return -1;
2094773703a5SCheng C Yang     }
2095773703a5SCheng C Yang 
2096773703a5SCheng C Yang     return 0;
2097773703a5SCheng C Yang }
2098773703a5SCheng C Yang 
2099e45333a8SKuiying Wang int getCRConfig(
2100e45333a8SKuiying Wang     ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2101e45333a8SKuiying Wang     const std::string& service = "xyz.openbmc_project.PSURedundancy",
2102773703a5SCheng C Yang     std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2103773703a5SCheng C Yang {
2104773703a5SCheng C Yang     boost::system::error_code ec;
2105773703a5SCheng C Yang     value = ctx->bus->yield_method_call<crConfigVariant>(
210619445ab7SYong Li         ctx->yield, ec, service,
2107773703a5SCheng C Yang         "/xyz/openbmc_project/control/power_supply_redundancy",
2108773703a5SCheng C Yang         "org.freedesktop.DBus.Properties", "Get",
2109773703a5SCheng C Yang         "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2110773703a5SCheng C Yang     if (ec)
2111773703a5SCheng C Yang     {
2112773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
2113773703a5SCheng C Yang             "Failed to get dbus property to cold redundancy");
2114773703a5SCheng C Yang         return -1;
2115773703a5SCheng C Yang     }
2116773703a5SCheng C Yang     return 0;
2117773703a5SCheng C Yang }
2118773703a5SCheng C Yang 
2119773703a5SCheng C Yang uint8_t getPSUCount(void)
2120773703a5SCheng C Yang {
2121773703a5SCheng C Yang     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2122773703a5SCheng C Yang     ipmi::Value num;
2123773703a5SCheng C Yang     try
2124773703a5SCheng C Yang     {
2125773703a5SCheng C Yang         num = ipmi::getDbusProperty(
2126773703a5SCheng C Yang             *dbus, "xyz.openbmc_project.PSURedundancy",
2127773703a5SCheng C Yang             "/xyz/openbmc_project/control/power_supply_redundancy",
2128773703a5SCheng C Yang             "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2129773703a5SCheng C Yang     }
2130773703a5SCheng C Yang     catch (sdbusplus::exception_t& e)
2131773703a5SCheng C Yang     {
2132773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
2133773703a5SCheng C Yang             "Failed to get PSUNumber property from dbus interface");
2134773703a5SCheng C Yang         return 0;
2135773703a5SCheng C Yang     }
2136773703a5SCheng C Yang     uint8_t* pNum = std::get_if<uint8_t>(&num);
2137773703a5SCheng C Yang     if (!pNum)
2138773703a5SCheng C Yang     {
2139773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
2140773703a5SCheng C Yang             "Error to get PSU Number");
2141773703a5SCheng C Yang         return 0;
2142773703a5SCheng C Yang     }
2143773703a5SCheng C Yang     return *pNum;
2144773703a5SCheng C Yang }
2145773703a5SCheng C Yang 
2146773703a5SCheng C Yang bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2147773703a5SCheng C Yang {
2148773703a5SCheng C Yang     if (conf.size() < num)
2149773703a5SCheng C Yang     {
2150773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
2151773703a5SCheng C Yang             "Invalid PSU Ranking");
2152773703a5SCheng C Yang         return false;
2153773703a5SCheng C Yang     }
2154773703a5SCheng C Yang     std::set<uint8_t> confSet;
2155773703a5SCheng C Yang     for (uint8_t i = 0; i < num; i++)
2156773703a5SCheng C Yang     {
2157773703a5SCheng C Yang         if (conf[i] > num)
2158773703a5SCheng C Yang         {
2159773703a5SCheng C Yang             phosphor::logging::log<phosphor::logging::level::ERR>(
2160773703a5SCheng C Yang                 "PSU Ranking is larger than current PSU number");
2161773703a5SCheng C Yang             return false;
2162773703a5SCheng C Yang         }
2163773703a5SCheng C Yang         confSet.emplace(conf[i]);
2164773703a5SCheng C Yang     }
2165773703a5SCheng C Yang 
2166773703a5SCheng C Yang     if (confSet.size() != num)
2167773703a5SCheng C Yang     {
2168773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
2169773703a5SCheng C Yang             "duplicate PSU Ranking");
2170773703a5SCheng C Yang         return false;
2171773703a5SCheng C Yang     }
2172773703a5SCheng C Yang     return true;
2173773703a5SCheng C Yang }
2174773703a5SCheng C Yang 
2175773703a5SCheng C Yang enum class crParameter
2176773703a5SCheng C Yang {
2177773703a5SCheng C Yang     crStatus = 0,
2178773703a5SCheng C Yang     crFeature = 1,
2179773703a5SCheng C Yang     rotationFeature = 2,
2180773703a5SCheng C Yang     rotationAlgo = 3,
2181773703a5SCheng C Yang     rotationPeriod = 4,
218219445ab7SYong Li     numOfPSU = 5,
218319445ab7SYong Li     rotationRankOrderEffective = 6
2184773703a5SCheng C Yang };
2185773703a5SCheng C Yang 
2186773703a5SCheng C Yang constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2187773703a5SCheng C Yang static const constexpr uint32_t oneDay = 0x15180;
2188773703a5SCheng C Yang static const constexpr uint32_t oneMonth = 0xf53700;
2189773703a5SCheng C Yang static const constexpr uint8_t userSpecific = 0x01;
2190773703a5SCheng C Yang static const constexpr uint8_t crSetCompleted = 0;
2191773703a5SCheng C Yang ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2192773703a5SCheng C Yang                                           uint8_t parameter,
2193773703a5SCheng C Yang                                           ipmi::message::Payload& payload)
2194773703a5SCheng C Yang {
2195773703a5SCheng C Yang     switch (static_cast<crParameter>(parameter))
2196773703a5SCheng C Yang     {
2197773703a5SCheng C Yang         case crParameter::rotationFeature:
2198773703a5SCheng C Yang         {
2199773703a5SCheng C Yang             uint8_t param1;
2200773703a5SCheng C Yang             if (payload.unpack(param1) || !payload.fullyUnpacked())
2201773703a5SCheng C Yang             {
2202773703a5SCheng C Yang                 return ipmi::responseReqDataLenInvalid();
2203773703a5SCheng C Yang             }
2204773703a5SCheng C Yang             // Rotation Enable can only be true or false
2205773703a5SCheng C Yang             if (param1 > 1)
2206773703a5SCheng C Yang             {
2207773703a5SCheng C Yang                 return ipmi::responseInvalidFieldRequest();
2208773703a5SCheng C Yang             }
2209773703a5SCheng C Yang             if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2210773703a5SCheng C Yang             {
2211773703a5SCheng C Yang                 return ipmi::responseResponseError();
2212773703a5SCheng C Yang             }
2213773703a5SCheng C Yang             break;
2214773703a5SCheng C Yang         }
2215773703a5SCheng C Yang         case crParameter::rotationAlgo:
2216773703a5SCheng C Yang         {
2217773703a5SCheng C Yang             // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2218773703a5SCheng C Yang             std::string algoName;
2219773703a5SCheng C Yang             uint8_t param1;
2220773703a5SCheng C Yang             if (payload.unpack(param1))
2221773703a5SCheng C Yang             {
2222773703a5SCheng C Yang                 return ipmi::responseReqDataLenInvalid();
2223773703a5SCheng C Yang             }
2224773703a5SCheng C Yang             switch (param1)
2225773703a5SCheng C Yang             {
2226773703a5SCheng C Yang                 case 0:
2227773703a5SCheng C Yang                     algoName = "xyz.openbmc_project.Control."
2228773703a5SCheng C Yang                                "PowerSupplyRedundancy.Algo.bmcSpecific";
2229773703a5SCheng C Yang                     break;
2230773703a5SCheng C Yang                 case 1:
2231773703a5SCheng C Yang                     algoName = "xyz.openbmc_project.Control."
2232773703a5SCheng C Yang                                "PowerSupplyRedundancy.Algo.userSpecific";
2233773703a5SCheng C Yang                     break;
2234773703a5SCheng C Yang                 default:
2235773703a5SCheng C Yang                     return ipmi::responseInvalidFieldRequest();
2236773703a5SCheng C Yang             }
2237773703a5SCheng C Yang             if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2238773703a5SCheng C Yang             {
2239773703a5SCheng C Yang                 return ipmi::responseResponseError();
2240773703a5SCheng C Yang             }
2241773703a5SCheng C Yang 
2242773703a5SCheng C Yang             uint8_t numberOfPSU = getPSUCount();
2243773703a5SCheng C Yang             if (!numberOfPSU)
2244773703a5SCheng C Yang             {
2245773703a5SCheng C Yang                 return ipmi::responseResponseError();
2246773703a5SCheng C Yang             }
2247773703a5SCheng C Yang             std::vector<uint8_t> rankOrder;
2248773703a5SCheng C Yang 
2249773703a5SCheng C Yang             if (param1 == userSpecific)
2250773703a5SCheng C Yang             {
2251773703a5SCheng C Yang                 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2252773703a5SCheng C Yang                 {
2253773703a5SCheng C Yang                     ipmi::responseReqDataLenInvalid();
2254773703a5SCheng C Yang                 }
225583315132SYong Li                 if (rankOrder.size() != numberOfPSU)
2256773703a5SCheng C Yang                 {
2257773703a5SCheng C Yang                     return ipmi::responseReqDataLenInvalid();
2258773703a5SCheng C Yang                 }
2259773703a5SCheng C Yang 
2260773703a5SCheng C Yang                 if (!validateCRAlgo(rankOrder, numberOfPSU))
2261773703a5SCheng C Yang                 {
2262773703a5SCheng C Yang                     return ipmi::responseInvalidFieldRequest();
2263773703a5SCheng C Yang                 }
2264773703a5SCheng C Yang             }
2265773703a5SCheng C Yang             else
2266773703a5SCheng C Yang             {
2267773703a5SCheng C Yang                 if (rankOrder.size() > 0)
2268773703a5SCheng C Yang                 {
2269773703a5SCheng C Yang                     return ipmi::responseReqDataLenInvalid();
2270773703a5SCheng C Yang                 }
2271773703a5SCheng C Yang                 for (uint8_t i = 1; i <= numberOfPSU; i++)
2272773703a5SCheng C Yang                 {
2273773703a5SCheng C Yang                     rankOrder.emplace_back(i);
2274773703a5SCheng C Yang                 }
2275773703a5SCheng C Yang             }
2276773703a5SCheng C Yang             if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2277773703a5SCheng C Yang             {
2278773703a5SCheng C Yang                 return ipmi::responseResponseError();
2279773703a5SCheng C Yang             }
2280773703a5SCheng C Yang             break;
2281773703a5SCheng C Yang         }
2282773703a5SCheng C Yang         case crParameter::rotationPeriod:
2283773703a5SCheng C Yang         {
2284773703a5SCheng C Yang             // Minimum Rotation period is  One day (86400 seconds) and Max
2285773703a5SCheng C Yang             // Rotation Period is 6 month (0xf53700 seconds)
2286773703a5SCheng C Yang             uint32_t period;
2287773703a5SCheng C Yang             if (payload.unpack(period) || !payload.fullyUnpacked())
2288773703a5SCheng C Yang             {
2289773703a5SCheng C Yang                 return ipmi::responseReqDataLenInvalid();
2290773703a5SCheng C Yang             }
2291773703a5SCheng C Yang             if ((period < oneDay) || (period > oneMonth))
2292773703a5SCheng C Yang             {
2293773703a5SCheng C Yang                 return ipmi::responseInvalidFieldRequest();
2294773703a5SCheng C Yang             }
2295773703a5SCheng C Yang             if (setCRConfig(ctx, "PeriodOfRotation", period))
2296773703a5SCheng C Yang             {
2297773703a5SCheng C Yang                 return ipmi::responseResponseError();
2298773703a5SCheng C Yang             }
2299773703a5SCheng C Yang             break;
2300773703a5SCheng C Yang         }
2301773703a5SCheng C Yang         default:
2302773703a5SCheng C Yang         {
2303773703a5SCheng C Yang             return ipmi::response(ccParameterNotSupported);
2304773703a5SCheng C Yang         }
2305773703a5SCheng C Yang     }
2306773703a5SCheng C Yang 
2307773703a5SCheng C Yang     return ipmi::responseSuccess(crSetCompleted);
2308773703a5SCheng C Yang }
2309773703a5SCheng C Yang 
231083315132SYong Li ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
2311773703a5SCheng C Yang     ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2312773703a5SCheng C Yang {
2313773703a5SCheng C Yang     crConfigVariant value;
2314773703a5SCheng C Yang     switch (static_cast<crParameter>(parameter))
2315773703a5SCheng C Yang     {
2316773703a5SCheng C Yang         case crParameter::crStatus:
2317773703a5SCheng C Yang         {
2318773703a5SCheng C Yang             if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2319773703a5SCheng C Yang             {
2320773703a5SCheng C Yang                 return ipmi::responseResponseError();
2321773703a5SCheng C Yang             }
2322773703a5SCheng C Yang             std::string* pStatus = std::get_if<std::string>(&value);
2323773703a5SCheng C Yang             if (!pStatus)
2324773703a5SCheng C Yang             {
2325773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2326773703a5SCheng C Yang                     "Error to get ColdRedundancyStatus property");
2327773703a5SCheng C Yang                 return ipmi::responseResponseError();
2328773703a5SCheng C Yang             }
2329773703a5SCheng C Yang             namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2330773703a5SCheng C Yang             auto status =
2331773703a5SCheng C Yang                 server::PowerSupplyRedundancy::convertStatusFromString(
2332773703a5SCheng C Yang                     *pStatus);
2333773703a5SCheng C Yang             switch (status)
2334773703a5SCheng C Yang             {
2335773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Status::inProgress:
2336f41e334dSCheng C Yang                     return ipmi::responseSuccess(parameter,
2337e45333a8SKuiying Wang                                                  static_cast<uint8_t>(1));
2338773703a5SCheng C Yang 
2339773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Status::completed:
2340f41e334dSCheng C Yang                     return ipmi::responseSuccess(parameter,
2341e45333a8SKuiying Wang                                                  static_cast<uint8_t>(0));
2342773703a5SCheng C Yang                 default:
2343773703a5SCheng C Yang                     phosphor::logging::log<phosphor::logging::level::ERR>(
2344773703a5SCheng C Yang                         "Error to get valid status");
2345773703a5SCheng C Yang                     return ipmi::responseResponseError();
2346773703a5SCheng C Yang             }
2347773703a5SCheng C Yang         }
2348773703a5SCheng C Yang         case crParameter::crFeature:
2349773703a5SCheng C Yang         {
2350e45333a8SKuiying Wang             if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
2351773703a5SCheng C Yang             {
2352773703a5SCheng C Yang                 return ipmi::responseResponseError();
2353773703a5SCheng C Yang             }
2354773703a5SCheng C Yang             bool* pResponse = std::get_if<bool>(&value);
2355773703a5SCheng C Yang             if (!pResponse)
2356773703a5SCheng C Yang             {
2357773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2358e45333a8SKuiying Wang                     "Error to get PowerSupplyRedundancyEnabled property");
2359773703a5SCheng C Yang                 return ipmi::responseResponseError();
2360773703a5SCheng C Yang             }
2361773703a5SCheng C Yang 
2362f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter,
2363f41e334dSCheng C Yang                                          static_cast<uint8_t>(*pResponse));
2364773703a5SCheng C Yang         }
2365773703a5SCheng C Yang         case crParameter::rotationFeature:
2366773703a5SCheng C Yang         {
2367773703a5SCheng C Yang             if (getCRConfig(ctx, "RotationEnabled", value))
2368773703a5SCheng C Yang             {
2369773703a5SCheng C Yang                 return ipmi::responseResponseError();
2370773703a5SCheng C Yang             }
2371773703a5SCheng C Yang             bool* pResponse = std::get_if<bool>(&value);
2372773703a5SCheng C Yang             if (!pResponse)
2373773703a5SCheng C Yang             {
2374773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2375773703a5SCheng C Yang                     "Error to get RotationEnabled property");
2376773703a5SCheng C Yang                 return ipmi::responseResponseError();
2377773703a5SCheng C Yang             }
2378f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter,
2379f41e334dSCheng C Yang                                          static_cast<uint8_t>(*pResponse));
2380773703a5SCheng C Yang         }
2381773703a5SCheng C Yang         case crParameter::rotationAlgo:
2382773703a5SCheng C Yang         {
2383773703a5SCheng C Yang             if (getCRConfig(ctx, "RotationAlgorithm", value))
2384773703a5SCheng C Yang             {
2385773703a5SCheng C Yang                 return ipmi::responseResponseError();
2386773703a5SCheng C Yang             }
2387773703a5SCheng C Yang 
2388773703a5SCheng C Yang             std::string* pAlgo = std::get_if<std::string>(&value);
2389773703a5SCheng C Yang             if (!pAlgo)
2390773703a5SCheng C Yang             {
2391773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2392773703a5SCheng C Yang                     "Error to get RotationAlgorithm property");
2393773703a5SCheng C Yang                 return ipmi::responseResponseError();
2394773703a5SCheng C Yang             }
239583315132SYong Li             std::vector<uint8_t> response;
2396773703a5SCheng C Yang             namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2397773703a5SCheng C Yang             auto algo =
2398773703a5SCheng C Yang                 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
239983315132SYong Li 
2400773703a5SCheng C Yang             switch (algo)
2401773703a5SCheng C Yang             {
2402773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
240383315132SYong Li                     response.push_back(0);
2404773703a5SCheng C Yang                     break;
2405773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Algo::userSpecific:
240683315132SYong Li                     response.push_back(1);
2407773703a5SCheng C Yang                     break;
2408773703a5SCheng C Yang                 default:
2409773703a5SCheng C Yang                     phosphor::logging::log<phosphor::logging::level::ERR>(
2410773703a5SCheng C Yang                         "Error to get valid algo");
2411773703a5SCheng C Yang                     return ipmi::responseResponseError();
2412773703a5SCheng C Yang             }
2413773703a5SCheng C Yang 
2414773703a5SCheng C Yang             if (getCRConfig(ctx, "RotationRankOrder", value))
2415773703a5SCheng C Yang             {
2416773703a5SCheng C Yang                 return ipmi::responseResponseError();
2417773703a5SCheng C Yang             }
2418773703a5SCheng C Yang             std::vector<uint8_t>* pResponse =
2419773703a5SCheng C Yang                 std::get_if<std::vector<uint8_t>>(&value);
2420773703a5SCheng C Yang             if (!pResponse)
2421773703a5SCheng C Yang             {
2422773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2423773703a5SCheng C Yang                     "Error to get RotationRankOrder property");
2424773703a5SCheng C Yang                 return ipmi::responseResponseError();
2425773703a5SCheng C Yang             }
242683315132SYong Li 
2427773703a5SCheng C Yang             std::copy(pResponse->begin(), pResponse->end(),
242883315132SYong Li                       std::back_inserter(response));
242983315132SYong Li 
2430f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter, response);
2431773703a5SCheng C Yang         }
2432773703a5SCheng C Yang         case crParameter::rotationPeriod:
2433773703a5SCheng C Yang         {
2434773703a5SCheng C Yang             if (getCRConfig(ctx, "PeriodOfRotation", value))
2435773703a5SCheng C Yang             {
2436773703a5SCheng C Yang                 return ipmi::responseResponseError();
2437773703a5SCheng C Yang             }
2438773703a5SCheng C Yang             uint32_t* pResponse = std::get_if<uint32_t>(&value);
2439773703a5SCheng C Yang             if (!pResponse)
2440773703a5SCheng C Yang             {
2441773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2442773703a5SCheng C Yang                     "Error to get RotationAlgorithm property");
2443773703a5SCheng C Yang                 return ipmi::responseResponseError();
2444773703a5SCheng C Yang             }
2445f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter, *pResponse);
2446773703a5SCheng C Yang         }
2447773703a5SCheng C Yang         case crParameter::numOfPSU:
2448773703a5SCheng C Yang         {
2449773703a5SCheng C Yang             uint8_t numberOfPSU = getPSUCount();
2450773703a5SCheng C Yang             if (!numberOfPSU)
2451773703a5SCheng C Yang             {
2452773703a5SCheng C Yang                 return ipmi::responseResponseError();
2453773703a5SCheng C Yang             }
2454f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter, numberOfPSU);
2455773703a5SCheng C Yang         }
245619445ab7SYong Li         case crParameter::rotationRankOrderEffective:
245719445ab7SYong Li         {
245819445ab7SYong Li             if (getCRConfig(ctx, "RotationRankOrder", value,
245919445ab7SYong Li                             "xyz.openbmc_project.PSURedundancy"))
246019445ab7SYong Li             {
246119445ab7SYong Li                 return ipmi::responseResponseError();
246219445ab7SYong Li             }
246319445ab7SYong Li             std::vector<uint8_t>* pResponse =
246419445ab7SYong Li                 std::get_if<std::vector<uint8_t>>(&value);
246519445ab7SYong Li             if (!pResponse)
246619445ab7SYong Li             {
246719445ab7SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
246819445ab7SYong Li                     "Error to get effective RotationRankOrder property");
246919445ab7SYong Li                 return ipmi::responseResponseError();
247019445ab7SYong Li             }
247119445ab7SYong Li             return ipmi::responseSuccess(parameter, *pResponse);
247219445ab7SYong Li         }
2473773703a5SCheng C Yang         default:
2474773703a5SCheng C Yang         {
2475773703a5SCheng C Yang             return ipmi::response(ccParameterNotSupported);
2476773703a5SCheng C Yang         }
2477773703a5SCheng C Yang     }
2478773703a5SCheng C Yang }
2479773703a5SCheng C Yang 
2480be560b09SZhu, Yunge ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2481be560b09SZhu, Yunge                                           uint8_t faultState,
2482be560b09SZhu, Yunge                                           uint8_t faultGroup,
2483be560b09SZhu, Yunge                                           std::array<uint8_t, 8>& ledStateData)
2484be560b09SZhu, Yunge {
2485be560b09SZhu, Yunge     constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2486be560b09SZhu, Yunge     static const std::array<std::string, maxFaultType> faultNames = {
2487be560b09SZhu, Yunge         "faultFan",       "faultTemp",     "faultPower",
2488be560b09SZhu, Yunge         "faultDriveSlot", "faultSoftware", "faultMemory"};
2489be560b09SZhu, Yunge 
2490be560b09SZhu, Yunge     constexpr uint8_t maxFaultSource = 0x4;
2491be560b09SZhu, Yunge     constexpr uint8_t skipLEDs = 0xFF;
2492be560b09SZhu, Yunge     constexpr uint8_t pinSize = 64;
2493be560b09SZhu, Yunge     constexpr uint8_t groupSize = 16;
2494ce4e73fdSZhikui Ren     constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
2495be560b09SZhu, Yunge 
2496ce4e73fdSZhikui Ren     // same pin names need to be defined in dts file
2497ce4e73fdSZhikui Ren     static const std::array<std::array<std::string, groupSize>, groupNum>
2498ce4e73fdSZhikui Ren         faultLedPinNames = {{
2499ce4e73fdSZhikui Ren             "LED_CPU1_CH1_DIMM1_FAULT",
2500ce4e73fdSZhikui Ren             "LED_CPU1_CH1_DIMM2_FAULT",
2501ce4e73fdSZhikui Ren             "LED_CPU1_CH2_DIMM1_FAULT",
2502ce4e73fdSZhikui Ren             "LED_CPU1_CH2_DIMM2_FAULT",
2503ce4e73fdSZhikui Ren             "LED_CPU1_CH3_DIMM1_FAULT",
2504ce4e73fdSZhikui Ren             "LED_CPU1_CH3_DIMM2_FAULT",
2505ce4e73fdSZhikui Ren             "LED_CPU1_CH4_DIMM1_FAULT",
2506ce4e73fdSZhikui Ren             "LED_CPU1_CH4_DIMM2_FAULT",
2507ce4e73fdSZhikui Ren             "LED_CPU1_CH5_DIMM1_FAULT",
2508ce4e73fdSZhikui Ren             "LED_CPU1_CH5_DIMM2_FAULT",
2509ce4e73fdSZhikui Ren             "LED_CPU1_CH6_DIMM1_FAULT",
2510ce4e73fdSZhikui Ren             "LED_CPU1_CH6_DIMM2_FAULT",
2511ce4e73fdSZhikui Ren             "",
2512ce4e73fdSZhikui Ren             "",
2513ce4e73fdSZhikui Ren             "",
2514ce4e73fdSZhikui Ren             "", // end of group1
2515ce4e73fdSZhikui Ren             "LED_CPU2_CH1_DIMM1_FAULT",
2516ce4e73fdSZhikui Ren             "LED_CPU2_CH1_DIMM2_FAULT",
2517ce4e73fdSZhikui Ren             "LED_CPU2_CH2_DIMM1_FAULT",
2518ce4e73fdSZhikui Ren             "LED_CPU2_CH2_DIMM2_FAULT",
2519ce4e73fdSZhikui Ren             "LED_CPU2_CH3_DIMM1_FAULT",
2520ce4e73fdSZhikui Ren             "LED_CPU2_CH3_DIMM2_FAULT",
2521ce4e73fdSZhikui Ren             "LED_CPU2_CH4_DIMM1_FAULT",
2522ce4e73fdSZhikui Ren             "LED_CPU2_CH4_DIMM2_FAULT",
2523ce4e73fdSZhikui Ren             "LED_CPU2_CH5_DIMM1_FAULT",
2524ce4e73fdSZhikui Ren             "LED_CPU2_CH5_DIMM2_FAULT",
2525ce4e73fdSZhikui Ren             "LED_CPU2_CH6_DIMM1_FAULT",
2526ce4e73fdSZhikui Ren             "LED_CPU2_CH6_DIMM2_FAULT",
2527ce4e73fdSZhikui Ren             "",
2528ce4e73fdSZhikui Ren             "",
2529ce4e73fdSZhikui Ren             "",
2530ce4e73fdSZhikui Ren             "", // endof group2
2531ce4e73fdSZhikui Ren             "LED_CPU3_CH1_DIMM1_FAULT",
2532ce4e73fdSZhikui Ren             "LED_CPU3_CH1_DIMM2_FAULT",
2533ce4e73fdSZhikui Ren             "LED_CPU3_CH2_DIMM1_FAULT",
2534ce4e73fdSZhikui Ren             "LED_CPU3_CH2_DIMM2_FAULT",
2535ce4e73fdSZhikui Ren             "LED_CPU3_CH3_DIMM1_FAULT",
2536ce4e73fdSZhikui Ren             "LED_CPU3_CH3_DIMM2_FAULT",
2537ce4e73fdSZhikui Ren             "LED_CPU3_CH4_DIMM1_FAULT",
2538ce4e73fdSZhikui Ren             "LED_CPU3_CH4_DIMM2_FAULT",
2539ce4e73fdSZhikui Ren             "LED_CPU3_CH5_DIMM1_FAULT",
2540ce4e73fdSZhikui Ren             "LED_CPU3_CH5_DIMM2_FAULT",
2541ce4e73fdSZhikui Ren             "LED_CPU3_CH6_DIMM1_FAULT",
2542ce4e73fdSZhikui Ren             "LED_CPU3_CH6_DIMM2_FAULT",
2543ce4e73fdSZhikui Ren             "",
2544ce4e73fdSZhikui Ren             "",
2545ce4e73fdSZhikui Ren             "",
2546ce4e73fdSZhikui Ren             "", // end of group3
2547ce4e73fdSZhikui Ren             "LED_CPU4_CH1_DIMM1_FAULT",
2548ce4e73fdSZhikui Ren             "LED_CPU4_CH1_DIMM2_FAULT",
2549ce4e73fdSZhikui Ren             "LED_CPU4_CH2_DIMM1_FAULT",
2550ce4e73fdSZhikui Ren             "LED_CPU4_CH2_DIMM2_FAULT",
2551ce4e73fdSZhikui Ren             "LED_CPU4_CH3_DIMM1_FAULT",
2552ce4e73fdSZhikui Ren             "LED_CPU4_CH3_DIMM2_FAULT",
2553ce4e73fdSZhikui Ren             "LED_CPU4_CH4_DIMM1_FAULT",
2554ce4e73fdSZhikui Ren             "LED_CPU4_CH4_DIMM2_FAULT",
2555ce4e73fdSZhikui Ren             "LED_CPU4_CH5_DIMM1_FAULT",
2556ce4e73fdSZhikui Ren             "LED_CPU4_CH5_DIMM2_FAULT",
2557ce4e73fdSZhikui Ren             "LED_CPU4_CH6_DIMM1_FAULT",
2558ce4e73fdSZhikui Ren             "LED_CPU4_CH6_DIMM2_FAULT",
2559ce4e73fdSZhikui Ren             "",
2560ce4e73fdSZhikui Ren             "",
2561ce4e73fdSZhikui Ren             "",
2562ce4e73fdSZhikui Ren             "", // end of group4
2563ce4e73fdSZhikui Ren             "LED_FAN1_FAULT",
2564ce4e73fdSZhikui Ren             "LED_FAN2_FAULT",
2565ce4e73fdSZhikui Ren             "LED_FAN3_FAULT",
2566ce4e73fdSZhikui Ren             "LED_FAN4_FAULT",
2567ce4e73fdSZhikui Ren             "LED_FAN5_FAULT",
2568ce4e73fdSZhikui Ren             "LED_FAN6_FAULT",
2569ce4e73fdSZhikui Ren             "LED_FAN7_FAULT",
2570ce4e73fdSZhikui Ren             "LED_FAN8_FAULT",
2571ce4e73fdSZhikui Ren             "",
2572ce4e73fdSZhikui Ren             "",
2573ce4e73fdSZhikui Ren             "",
2574ce4e73fdSZhikui Ren             "",
2575ce4e73fdSZhikui Ren             "",
2576ce4e73fdSZhikui Ren             "",
2577ce4e73fdSZhikui Ren             "",
2578ce4e73fdSZhikui Ren             "" // end of group5
2579ce4e73fdSZhikui Ren         }};
2580be560b09SZhu, Yunge 
2581ce4e73fdSZhikui Ren     // Validate the source, fault type --
2582ce4e73fdSZhikui Ren     // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2583ce4e73fdSZhikui Ren     // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2584ce4e73fdSZhikui Ren     // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2585ce4e73fdSZhikui Ren     // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2586ce4e73fdSZhikui Ren     // definition differs based on fault type (Byte 2)
2587ce4e73fdSZhikui Ren     //          Type Fan=> Group: 0=FanGroupID, FF-not used
2588ce4e73fdSZhikui Ren     //                  Byte 5-11 00h, not used
2589ce4e73fdSZhikui Ren     //                  Byte12 FanLedState [7:0]-Fans 7:0
2590ce4e73fdSZhikui Ren     //          Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2591ce4e73fdSZhikui Ren     //                  Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2592ce4e73fdSZhikui Ren     //                  [63:48] = CPU4 channels 7:0, 2 bits per channel
2593ce4e73fdSZhikui Ren     //                  [47:32] = CPU3 channels 7:0, 2 bits per channel
2594ce4e73fdSZhikui Ren     //                  [31:16] = CPU2 channels 7:0, 2 bits per channel
2595ce4e73fdSZhikui Ren     //                  [15:0] =  CPU1 channels 7:0, 2 bits per channel
2596ce4e73fdSZhikui Ren     //          Type Other=> Component Fault LED Group ID, not used set to 0xFF
2597ce4e73fdSZhikui Ren     //                  Byte[5:12]: reserved 0x00h
2598be560b09SZhu, Yunge     if ((sourceId >= maxFaultSource) ||
2599be560b09SZhu, Yunge         (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2600be560b09SZhu, Yunge         (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2601be560b09SZhu, Yunge         (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2602be560b09SZhu, Yunge     {
2603be560b09SZhu, Yunge         return ipmi::responseParmOutOfRange();
2604be560b09SZhu, Yunge     }
2605be560b09SZhu, Yunge 
2606ce4e73fdSZhikui Ren     size_t pinGroupOffset = 0;
2607ce4e73fdSZhikui Ren     size_t pinGroupMax = pinSize / groupSize;
2608ce4e73fdSZhikui Ren     if (RemoteFaultType::fan == RemoteFaultType(faultType))
2609be560b09SZhu, Yunge     {
2610ce4e73fdSZhikui Ren         pinGroupOffset = 4;
2611ce4e73fdSZhikui Ren         pinGroupMax = groupNum - pinSize / groupSize;
2612be560b09SZhu, Yunge     }
2613be560b09SZhu, Yunge 
2614be560b09SZhu, Yunge     switch (RemoteFaultType(faultType))
2615be560b09SZhu, Yunge     {
2616be560b09SZhu, Yunge         case (RemoteFaultType::fan):
2617be560b09SZhu, Yunge         case (RemoteFaultType::memory):
2618be560b09SZhu, Yunge         {
2619be560b09SZhu, Yunge             if (faultGroup == skipLEDs)
2620be560b09SZhu, Yunge             {
2621be560b09SZhu, Yunge                 return ipmi::responseSuccess();
2622be560b09SZhu, Yunge             }
2623be560b09SZhu, Yunge             // calculate led state bit filed count, each byte has 8bits
2624be560b09SZhu, Yunge             // the maximum bits will be 8 * 8 bits
2625be560b09SZhu, Yunge             constexpr uint8_t size = sizeof(ledStateData) * 8;
2626ce4e73fdSZhikui Ren 
2627ce4e73fdSZhikui Ren             // assemble ledState
2628ce4e73fdSZhikui Ren             uint64_t ledState = 0;
2629ce4e73fdSZhikui Ren             bool hasError = false;
2630be560b09SZhu, Yunge             for (int i = 0; i < sizeof(ledStateData); i++)
2631be560b09SZhu, Yunge             {
2632be560b09SZhu, Yunge                 ledState = (uint64_t)(ledState << 8);
2633be560b09SZhu, Yunge                 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2634be560b09SZhu, Yunge             }
2635be560b09SZhu, Yunge             std::bitset<size> ledStateBits(ledState);
2636ce4e73fdSZhikui Ren 
2637ce4e73fdSZhikui Ren             for (int group = 0; group < pinGroupMax; group++)
2638ce4e73fdSZhikui Ren             {
2639ce4e73fdSZhikui Ren                 for (int i = 0; i < groupSize; i++)
2640ce4e73fdSZhikui Ren                 { // skip non-existing pins
2641ce4e73fdSZhikui Ren                     if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2642be560b09SZhu, Yunge                     {
2643be560b09SZhu, Yunge                         continue;
2644be560b09SZhu, Yunge                     }
2645be560b09SZhu, Yunge 
2646ce4e73fdSZhikui Ren                     gpiod::line line = gpiod::find_line(
2647ce4e73fdSZhikui Ren                         faultLedPinNames[group + pinGroupOffset][i]);
2648ce4e73fdSZhikui Ren                     if (!line)
2649be560b09SZhu, Yunge                     {
2650be560b09SZhu, Yunge                         phosphor::logging::log<phosphor::logging::level::ERR>(
2651be560b09SZhu, Yunge                             "Not Find Led Gpio Device!",
2652ce4e73fdSZhikui Ren                             phosphor::logging::entry(
2653ce4e73fdSZhikui Ren                                 "DEVICE=%s",
2654ce4e73fdSZhikui Ren                                 faultLedPinNames[group + pinGroupOffset][i]
2655ce4e73fdSZhikui Ren                                     .c_str()));
2656ce4e73fdSZhikui Ren                         hasError = true;
2657ce4e73fdSZhikui Ren                         continue;
2658be560b09SZhu, Yunge                     }
2659ce4e73fdSZhikui Ren 
2660ce4e73fdSZhikui Ren                     bool activeHigh =
2661ce4e73fdSZhikui Ren                         (line.active_state() == gpiod::line::ACTIVE_HIGH);
2662ce4e73fdSZhikui Ren                     try
2663ce4e73fdSZhikui Ren                     {
2664ce4e73fdSZhikui Ren                         line.request(
2665ce4e73fdSZhikui Ren                             {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2666ce4e73fdSZhikui Ren                              activeHigh
2667ce4e73fdSZhikui Ren                                  ? 0
2668ce4e73fdSZhikui Ren                                  : gpiod::line_request::FLAG_ACTIVE_LOW});
2669ce4e73fdSZhikui Ren                         line.set_value(ledStateBits[i + group * groupSize]);
2670ce4e73fdSZhikui Ren                     }
2671ce4e73fdSZhikui Ren                     catch (std::system_error&)
2672ce4e73fdSZhikui Ren                     {
2673ce4e73fdSZhikui Ren                         phosphor::logging::log<phosphor::logging::level::ERR>(
2674ce4e73fdSZhikui Ren                             "Error write Led Gpio Device!",
2675ce4e73fdSZhikui Ren                             phosphor::logging::entry(
2676ce4e73fdSZhikui Ren                                 "DEVICE=%s",
2677ce4e73fdSZhikui Ren                                 faultLedPinNames[group + pinGroupOffset][i]
2678ce4e73fdSZhikui Ren                                     .c_str()));
2679ce4e73fdSZhikui Ren                         hasError = true;
2680ce4e73fdSZhikui Ren                         continue;
2681ce4e73fdSZhikui Ren                     }
2682ce4e73fdSZhikui Ren                 } // for int i
2683ce4e73fdSZhikui Ren             }
2684ce4e73fdSZhikui Ren             if (hasError)
2685ce4e73fdSZhikui Ren             {
2686ce4e73fdSZhikui Ren                 return ipmi::responseResponseError();
2687be560b09SZhu, Yunge             }
2688be560b09SZhu, Yunge             break;
2689be560b09SZhu, Yunge         }
2690be560b09SZhu, Yunge         default:
2691be560b09SZhu, Yunge         {
2692be560b09SZhu, Yunge             // now only support two fault types
2693be560b09SZhu, Yunge             return ipmi::responseParmOutOfRange();
2694be560b09SZhu, Yunge         }
2695ce4e73fdSZhikui Ren     } // switch
2696be560b09SZhu, Yunge     return ipmi::responseSuccess();
2697be560b09SZhu, Yunge }
2698be560b09SZhu, Yunge 
2699ea537d53SRichard Marian Thomaiyar ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2700ea537d53SRichard Marian Thomaiyar {
2701ea537d53SRichard Marian Thomaiyar     uint8_t prodId = 0;
2702ea537d53SRichard Marian Thomaiyar     try
2703ea537d53SRichard Marian Thomaiyar     {
270415419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2705ea537d53SRichard Marian Thomaiyar         const DbusObjectInfo& object = getDbusObject(
270615419dd5SVernon Mauery             *dbus, "xyz.openbmc_project.Inventory.Item.Board",
2707ea537d53SRichard Marian Thomaiyar             "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2708ea537d53SRichard Marian Thomaiyar         const Value& propValue = getDbusProperty(
270915419dd5SVernon Mauery             *dbus, object.second, object.first,
27106c57e5caSSuryakanth Sekar             "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
27116c57e5caSSuryakanth Sekar             "ProductId");
2712ea537d53SRichard Marian Thomaiyar         prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2713ea537d53SRichard Marian Thomaiyar     }
2714ea537d53SRichard Marian Thomaiyar     catch (std::exception& e)
2715ea537d53SRichard Marian Thomaiyar     {
2716ea537d53SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2717ea537d53SRichard Marian Thomaiyar             "ipmiOEMReadBoardProductId: Product ID read failed!",
2718ea537d53SRichard Marian Thomaiyar             phosphor::logging::entry("ERR=%s", e.what()));
2719ea537d53SRichard Marian Thomaiyar     }
2720ea537d53SRichard Marian Thomaiyar     return ipmi::responseSuccess(prodId);
2721ea537d53SRichard Marian Thomaiyar }
2722ea537d53SRichard Marian Thomaiyar 
2723d801e463SRichard Marian Thomaiyar /** @brief implements the get security mode command
2724d801e463SRichard Marian Thomaiyar  *  @param ctx - ctx pointer
2725d801e463SRichard Marian Thomaiyar  *
2726d801e463SRichard Marian Thomaiyar  *  @returns IPMI completion code with following data
2727d801e463SRichard Marian Thomaiyar  *   - restriction mode value - As specified in
2728d801e463SRichard Marian Thomaiyar  * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2729d801e463SRichard Marian Thomaiyar  *   - special mode value - As specified in
2730d801e463SRichard Marian Thomaiyar  * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2731d801e463SRichard Marian Thomaiyar  */
2732d801e463SRichard Marian Thomaiyar ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2733d801e463SRichard Marian Thomaiyar {
2734d801e463SRichard Marian Thomaiyar     namespace securityNameSpace =
2735d801e463SRichard Marian Thomaiyar         sdbusplus::xyz::openbmc_project::Control::Security::server;
2736d801e463SRichard Marian Thomaiyar     uint8_t restrictionModeValue = 0;
2737d801e463SRichard Marian Thomaiyar     uint8_t specialModeValue = 0;
2738d801e463SRichard Marian Thomaiyar 
2739d801e463SRichard Marian Thomaiyar     boost::system::error_code ec;
2740d801e463SRichard Marian Thomaiyar     auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
274128c7290cSJames Feist         ctx->yield, ec, restricionModeService, restricionModeBasePath,
2742d801e463SRichard Marian Thomaiyar         dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2743d801e463SRichard Marian Thomaiyar         restricionModeProperty);
2744d801e463SRichard Marian Thomaiyar     if (ec)
2745d801e463SRichard Marian Thomaiyar     {
2746d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2747d801e463SRichard Marian Thomaiyar             "ipmiGetSecurityMode: failed to get RestrictionMode property",
2748d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2749d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2750d801e463SRichard Marian Thomaiyar     }
2751d801e463SRichard Marian Thomaiyar     restrictionModeValue = static_cast<uint8_t>(
2752d801e463SRichard Marian Thomaiyar         securityNameSpace::RestrictionMode::convertModesFromString(
2753d801e463SRichard Marian Thomaiyar             std::get<std::string>(varRestrMode)));
27548d4f8d73SRichard Marian Thomaiyar     auto varSpecialMode =
27558d4f8d73SRichard Marian Thomaiyar         ctx->bus->yield_method_call<std::variant<std::string>>(
275628c7290cSJames Feist             ctx->yield, ec, specialModeService, specialModeBasePath,
2757d801e463SRichard Marian Thomaiyar             dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2758d801e463SRichard Marian Thomaiyar             specialModeProperty);
2759d801e463SRichard Marian Thomaiyar     if (ec)
2760d801e463SRichard Marian Thomaiyar     {
2761d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2762d801e463SRichard Marian Thomaiyar             "ipmiGetSecurityMode: failed to get SpecialMode property",
2763d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2764d801e463SRichard Marian Thomaiyar         // fall through, let us not worry about SpecialMode property, which is
2765d801e463SRichard Marian Thomaiyar         // not required in user scenario
2766d801e463SRichard Marian Thomaiyar     }
2767d801e463SRichard Marian Thomaiyar     else
2768d801e463SRichard Marian Thomaiyar     {
27698d4f8d73SRichard Marian Thomaiyar         specialModeValue = static_cast<uint8_t>(
27708d4f8d73SRichard Marian Thomaiyar             securityNameSpace::SpecialMode::convertModesFromString(
27718d4f8d73SRichard Marian Thomaiyar                 std::get<std::string>(varSpecialMode)));
2772d801e463SRichard Marian Thomaiyar     }
2773d801e463SRichard Marian Thomaiyar     return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2774d801e463SRichard Marian Thomaiyar }
2775d801e463SRichard Marian Thomaiyar 
2776d801e463SRichard Marian Thomaiyar /** @brief implements the set security mode command
2777d801e463SRichard Marian Thomaiyar  *  Command allows to upgrade the restriction mode and won't allow
2778d801e463SRichard Marian Thomaiyar  *  to downgrade from system interface
2779d801e463SRichard Marian Thomaiyar  *  @param ctx - ctx pointer
2780d801e463SRichard Marian Thomaiyar  *  @param restrictionMode - restriction mode value to be set.
2781d801e463SRichard Marian Thomaiyar  *
2782d801e463SRichard Marian Thomaiyar  *  @returns IPMI completion code
2783d801e463SRichard Marian Thomaiyar  */
2784d801e463SRichard Marian Thomaiyar ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
278510791062SRichard Marian Thomaiyar                                     uint8_t restrictionMode,
278610791062SRichard Marian Thomaiyar                                     std::optional<uint8_t> specialMode)
2787d801e463SRichard Marian Thomaiyar {
278810791062SRichard Marian Thomaiyar #ifndef BMC_VALIDATION_UNSECURE_FEATURE
278910791062SRichard Marian Thomaiyar     if (specialMode)
279010791062SRichard Marian Thomaiyar     {
279110791062SRichard Marian Thomaiyar         return ipmi::responseReqDataLenInvalid();
279210791062SRichard Marian Thomaiyar     }
279310791062SRichard Marian Thomaiyar #endif
2794d801e463SRichard Marian Thomaiyar     namespace securityNameSpace =
2795d801e463SRichard Marian Thomaiyar         sdbusplus::xyz::openbmc_project::Control::Security::server;
2796d801e463SRichard Marian Thomaiyar 
2797d801e463SRichard Marian Thomaiyar     ChannelInfo chInfo;
2798d801e463SRichard Marian Thomaiyar     if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2799d801e463SRichard Marian Thomaiyar     {
2800d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2801d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode: Failed to get Channel Info",
2802d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2803d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2804d801e463SRichard Marian Thomaiyar     }
2805d801e463SRichard Marian Thomaiyar     auto reqMode =
2806d801e463SRichard Marian Thomaiyar         static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2807d801e463SRichard Marian Thomaiyar 
2808d801e463SRichard Marian Thomaiyar     if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2809d801e463SRichard Marian Thomaiyar         (reqMode >
2810d801e463SRichard Marian Thomaiyar          securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2811d801e463SRichard Marian Thomaiyar     {
2812d801e463SRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
2813d801e463SRichard Marian Thomaiyar     }
2814d801e463SRichard Marian Thomaiyar 
2815d801e463SRichard Marian Thomaiyar     boost::system::error_code ec;
2816d801e463SRichard Marian Thomaiyar     auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
281728c7290cSJames Feist         ctx->yield, ec, restricionModeService, restricionModeBasePath,
2818d801e463SRichard Marian Thomaiyar         dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2819d801e463SRichard Marian Thomaiyar         restricionModeProperty);
2820d801e463SRichard Marian Thomaiyar     if (ec)
2821d801e463SRichard Marian Thomaiyar     {
2822d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2823d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode: failed to get RestrictionMode property",
2824d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2825d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2826d801e463SRichard Marian Thomaiyar     }
2827d801e463SRichard Marian Thomaiyar     auto currentRestrictionMode =
2828d801e463SRichard Marian Thomaiyar         securityNameSpace::RestrictionMode::convertModesFromString(
2829d801e463SRichard Marian Thomaiyar             std::get<std::string>(varRestrMode));
2830d801e463SRichard Marian Thomaiyar 
2831d801e463SRichard Marian Thomaiyar     if (chInfo.mediumType !=
2832d801e463SRichard Marian Thomaiyar             static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2833d801e463SRichard Marian Thomaiyar         currentRestrictionMode > reqMode)
2834d801e463SRichard Marian Thomaiyar     {
2835d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2836d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode - Downgrading security mode not supported "
2837d801e463SRichard Marian Thomaiyar             "through system interface",
2838d801e463SRichard Marian Thomaiyar             phosphor::logging::entry(
2839d801e463SRichard Marian Thomaiyar                 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2840d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2841d801e463SRichard Marian Thomaiyar         return ipmi::responseCommandNotAvailable();
2842d801e463SRichard Marian Thomaiyar     }
2843d801e463SRichard Marian Thomaiyar 
2844d801e463SRichard Marian Thomaiyar     ec.clear();
2845d801e463SRichard Marian Thomaiyar     ctx->bus->yield_method_call<>(
284628c7290cSJames Feist         ctx->yield, ec, restricionModeService, restricionModeBasePath,
2847d801e463SRichard Marian Thomaiyar         dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2848d801e463SRichard Marian Thomaiyar         restricionModeProperty,
2849d801e463SRichard Marian Thomaiyar         static_cast<std::variant<std::string>>(
2850d801e463SRichard Marian Thomaiyar             securityNameSpace::convertForMessage(reqMode)));
2851d801e463SRichard Marian Thomaiyar 
2852d801e463SRichard Marian Thomaiyar     if (ec)
2853d801e463SRichard Marian Thomaiyar     {
2854d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2855d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode: failed to set RestrictionMode property",
2856d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2857d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2858d801e463SRichard Marian Thomaiyar     }
285910791062SRichard Marian Thomaiyar 
286010791062SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE
286110791062SRichard Marian Thomaiyar     if (specialMode)
286210791062SRichard Marian Thomaiyar     {
2863d77489f1SJayaprakash Mutyala         constexpr uint8_t mfgMode = 0x01;
2864d77489f1SJayaprakash Mutyala         // Manufacturing mode is reserved. So can't enable this mode.
2865d77489f1SJayaprakash Mutyala         if (specialMode.value() == mfgMode)
2866d77489f1SJayaprakash Mutyala         {
2867d77489f1SJayaprakash Mutyala             phosphor::logging::log<phosphor::logging::level::INFO>(
2868d77489f1SJayaprakash Mutyala                 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
2869d77489f1SJayaprakash Mutyala             return ipmi::responseInvalidFieldRequest();
2870d77489f1SJayaprakash Mutyala         }
2871d77489f1SJayaprakash Mutyala 
287210791062SRichard Marian Thomaiyar         ec.clear();
287310791062SRichard Marian Thomaiyar         ctx->bus->yield_method_call<>(
287410791062SRichard Marian Thomaiyar             ctx->yield, ec, specialModeService, specialModeBasePath,
287510791062SRichard Marian Thomaiyar             dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
287610791062SRichard Marian Thomaiyar             specialModeProperty,
287710791062SRichard Marian Thomaiyar             static_cast<std::variant<std::string>>(
287810791062SRichard Marian Thomaiyar                 securityNameSpace::convertForMessage(
287910791062SRichard Marian Thomaiyar                     static_cast<securityNameSpace::SpecialMode::Modes>(
288010791062SRichard Marian Thomaiyar                         specialMode.value()))));
288110791062SRichard Marian Thomaiyar 
288210791062SRichard Marian Thomaiyar         if (ec)
288310791062SRichard Marian Thomaiyar         {
288410791062SRichard Marian Thomaiyar             phosphor::logging::log<phosphor::logging::level::ERR>(
288510791062SRichard Marian Thomaiyar                 "ipmiSetSecurityMode: failed to set SpecialMode property",
288610791062SRichard Marian Thomaiyar                 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
288710791062SRichard Marian Thomaiyar             return ipmi::responseUnspecifiedError();
288810791062SRichard Marian Thomaiyar         }
288910791062SRichard Marian Thomaiyar     }
289010791062SRichard Marian Thomaiyar #endif
2891d801e463SRichard Marian Thomaiyar     return ipmi::responseSuccess();
2892d801e463SRichard Marian Thomaiyar }
2893d801e463SRichard Marian Thomaiyar 
28944ac799d7SVernon Mauery ipmi::RspType<uint8_t /* restore status */>
28954ac799d7SVernon Mauery     ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
28964ac799d7SVernon Mauery {
28974ac799d7SVernon Mauery     static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
28984ac799d7SVernon Mauery 
28994ac799d7SVernon Mauery     if (clr != expClr)
29004ac799d7SVernon Mauery     {
29014ac799d7SVernon Mauery         return ipmi::responseInvalidFieldRequest();
29024ac799d7SVernon Mauery     }
29034ac799d7SVernon Mauery     constexpr uint8_t cmdStatus = 0;
29044ac799d7SVernon Mauery     constexpr uint8_t cmdDefaultRestore = 0xaa;
29054ac799d7SVernon Mauery     constexpr uint8_t cmdFullRestore = 0xbb;
29064ac799d7SVernon Mauery     constexpr uint8_t cmdFormat = 0xcc;
29074ac799d7SVernon Mauery 
29084ac799d7SVernon Mauery     constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
29094ac799d7SVernon Mauery 
29104ac799d7SVernon Mauery     switch (cmd)
29114ac799d7SVernon Mauery     {
29124ac799d7SVernon Mauery         case cmdStatus:
29134ac799d7SVernon Mauery             break;
29144ac799d7SVernon Mauery         case cmdDefaultRestore:
29154ac799d7SVernon Mauery         case cmdFullRestore:
29164ac799d7SVernon Mauery         case cmdFormat:
29174ac799d7SVernon Mauery         {
29184ac799d7SVernon Mauery             // write file to rwfs root
29194ac799d7SVernon Mauery             int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
29204ac799d7SVernon Mauery             std::ofstream restoreFile(restoreOpFname);
29214ac799d7SVernon Mauery             if (!restoreFile)
29224ac799d7SVernon Mauery             {
29234ac799d7SVernon Mauery                 return ipmi::responseUnspecifiedError();
29244ac799d7SVernon Mauery             }
29254ac799d7SVernon Mauery             restoreFile << value << "\n";
2926ba1fbc89SArun P. Mohanan 
2927ba1fbc89SArun P. Mohanan             phosphor::logging::log<phosphor::logging::level::WARNING>(
2928ba1fbc89SArun P. Mohanan                 "Restore to default will be performed on next BMC boot",
2929ba1fbc89SArun P. Mohanan                 phosphor::logging::entry("ACTION=0x%0X", cmd));
2930ba1fbc89SArun P. Mohanan 
29314ac799d7SVernon Mauery             break;
29324ac799d7SVernon Mauery         }
29334ac799d7SVernon Mauery         default:
29344ac799d7SVernon Mauery             return ipmi::responseInvalidFieldRequest();
29354ac799d7SVernon Mauery     }
29364ac799d7SVernon Mauery 
29374ac799d7SVernon Mauery     constexpr uint8_t restorePending = 0;
29384ac799d7SVernon Mauery     constexpr uint8_t restoreComplete = 1;
29394ac799d7SVernon Mauery 
29404ac799d7SVernon Mauery     uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
29414ac799d7SVernon Mauery                                 ? restorePending
29424ac799d7SVernon Mauery                                 : restoreComplete;
29434ac799d7SVernon Mauery     return ipmi::responseSuccess(restoreStatus);
29444ac799d7SVernon Mauery }
29454ac799d7SVernon Mauery 
294639736d59SChen Yugang ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
294739736d59SChen Yugang {
294839736d59SChen Yugang     uint8_t bmcSource;
294997cf96e6SChen Yugang     namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
295039736d59SChen Yugang 
295139736d59SChen Yugang     try
295239736d59SChen Yugang     {
295339736d59SChen Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
295439736d59SChen Yugang         std::string service =
295539736d59SChen Yugang             getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
295639736d59SChen Yugang         Value variant =
295739736d59SChen Yugang             getDbusProperty(*dbus, service, oemNmiSourceObjPath,
295839736d59SChen Yugang                             oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
295939736d59SChen Yugang 
296039736d59SChen Yugang         switch (nmi::NMISource::convertBMCSourceSignalFromString(
296139736d59SChen Yugang             std::get<std::string>(variant)))
296239736d59SChen Yugang         {
296339736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::None:
296439736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::none);
296539736d59SChen Yugang                 break;
296697cf96e6SChen Yugang             case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
296797cf96e6SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
296839736d59SChen Yugang                 break;
296997cf96e6SChen Yugang             case nmi::NMISource::BMCSourceSignal::Watchdog:
297097cf96e6SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
297139736d59SChen Yugang                 break;
297239736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::ChassisCmd:
297339736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
297439736d59SChen Yugang                 break;
297539736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::MemoryError:
297639736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
297739736d59SChen Yugang                 break;
297897cf96e6SChen Yugang             case nmi::NMISource::BMCSourceSignal::PciBusError:
297997cf96e6SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
298039736d59SChen Yugang                 break;
298197cf96e6SChen Yugang             case nmi::NMISource::BMCSourceSignal::PCH:
298297cf96e6SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::pch);
298339736d59SChen Yugang                 break;
298497cf96e6SChen Yugang             case nmi::NMISource::BMCSourceSignal::Chipset:
298597cf96e6SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
298639736d59SChen Yugang                 break;
298739736d59SChen Yugang             default:
298839736d59SChen Yugang                 phosphor::logging::log<phosphor::logging::level::ERR>(
298939736d59SChen Yugang                     "NMI source: invalid property!",
299039736d59SChen Yugang                     phosphor::logging::entry(
299139736d59SChen Yugang                         "PROP=%s", std::get<std::string>(variant).c_str()));
299239736d59SChen Yugang                 return ipmi::responseResponseError();
299339736d59SChen Yugang         }
299439736d59SChen Yugang     }
299539736d59SChen Yugang     catch (sdbusplus::exception::SdBusError& e)
299639736d59SChen Yugang     {
299739736d59SChen Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
299839736d59SChen Yugang         return ipmi::responseResponseError();
299939736d59SChen Yugang     }
300039736d59SChen Yugang 
300139736d59SChen Yugang     return ipmi::responseSuccess(bmcSource);
300239736d59SChen Yugang }
300339736d59SChen Yugang 
300439736d59SChen Yugang ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
300539736d59SChen Yugang {
300697cf96e6SChen Yugang     namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
300739736d59SChen Yugang 
300839736d59SChen Yugang     nmi::NMISource::BMCSourceSignal bmcSourceSignal =
300939736d59SChen Yugang         nmi::NMISource::BMCSourceSignal::None;
301039736d59SChen Yugang 
301139736d59SChen Yugang     switch (NmiSource(sourceId))
301239736d59SChen Yugang     {
301339736d59SChen Yugang         case NmiSource::none:
301439736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
301539736d59SChen Yugang             break;
301697cf96e6SChen Yugang         case NmiSource::frontPanelButton:
301797cf96e6SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
301839736d59SChen Yugang             break;
301997cf96e6SChen Yugang         case NmiSource::watchdog:
302097cf96e6SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
302139736d59SChen Yugang             break;
302239736d59SChen Yugang         case NmiSource::chassisCmd:
302339736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
302439736d59SChen Yugang             break;
302539736d59SChen Yugang         case NmiSource::memoryError:
302639736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
302739736d59SChen Yugang             break;
302897cf96e6SChen Yugang         case NmiSource::pciBusError:
302997cf96e6SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
303039736d59SChen Yugang             break;
303197cf96e6SChen Yugang         case NmiSource::pch:
303297cf96e6SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
303339736d59SChen Yugang             break;
303497cf96e6SChen Yugang         case NmiSource::chipset:
303597cf96e6SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
303639736d59SChen Yugang             break;
303739736d59SChen Yugang         default:
303839736d59SChen Yugang             phosphor::logging::log<phosphor::logging::level::ERR>(
303939736d59SChen Yugang                 "NMI source: invalid property!");
304039736d59SChen Yugang             return ipmi::responseResponseError();
304139736d59SChen Yugang     }
304239736d59SChen Yugang 
304339736d59SChen Yugang     try
304439736d59SChen Yugang     {
304539736d59SChen Yugang         // keep NMI signal source
304639736d59SChen Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
304739736d59SChen Yugang         std::string service =
304839736d59SChen Yugang             getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
304997cf96e6SChen Yugang         setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
305039736d59SChen Yugang                         oemNmiBmcSourceObjPathProp,
305197cf96e6SChen Yugang                         nmi::convertForMessage(bmcSourceSignal));
305299be6330SChen Yugang         // set Enabled property to inform NMI source handling
305399be6330SChen Yugang         // to trigger a NMI_OUT BSOD.
305499be6330SChen Yugang         // if it's triggered by NMI source property changed,
305599be6330SChen Yugang         // NMI_OUT BSOD could be missed if the same source occurs twice in a row
305699be6330SChen Yugang         if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
305799be6330SChen Yugang         {
305899be6330SChen Yugang             setDbusProperty(*dbus, service, oemNmiSourceObjPath,
305999be6330SChen Yugang                             oemNmiSourceIntf, oemNmiEnabledObjPathProp,
306099be6330SChen Yugang                             static_cast<bool>(true));
306199be6330SChen Yugang         }
306239736d59SChen Yugang     }
306339736d59SChen Yugang     catch (sdbusplus::exception_t& e)
306439736d59SChen Yugang     {
306539736d59SChen Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
306639736d59SChen Yugang         return ipmi::responseResponseError();
306739736d59SChen Yugang     }
306839736d59SChen Yugang 
306939736d59SChen Yugang     return ipmi::responseSuccess();
307039736d59SChen Yugang }
307139736d59SChen Yugang 
307263efafacSJames Feist namespace dimmOffset
307363efafacSJames Feist {
307463efafacSJames Feist constexpr const char* dimmPower = "DimmPower";
307563efafacSJames Feist constexpr const char* staticCltt = "StaticCltt";
307663efafacSJames Feist constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
307763efafacSJames Feist constexpr const char* offsetInterface =
307863efafacSJames Feist     "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
307963efafacSJames Feist constexpr const char* property = "DimmOffset";
308063efafacSJames Feist 
308163efafacSJames Feist }; // namespace dimmOffset
308263efafacSJames Feist 
308363efafacSJames Feist ipmi::RspType<>
308463efafacSJames Feist     ipmiOEMSetDimmOffset(uint8_t type,
308563efafacSJames Feist                          const std::vector<std::tuple<uint8_t, uint8_t>>& data)
308663efafacSJames Feist {
308763efafacSJames Feist     if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
308863efafacSJames Feist         type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
308963efafacSJames Feist     {
309063efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
309163efafacSJames Feist     }
309263efafacSJames Feist 
309363efafacSJames Feist     if (data.empty())
309463efafacSJames Feist     {
309563efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
309663efafacSJames Feist     }
309763efafacSJames Feist     nlohmann::json json;
309863efafacSJames Feist 
309963efafacSJames Feist     std::ifstream jsonStream(dimmOffsetFile);
310063efafacSJames Feist     if (jsonStream.good())
310163efafacSJames Feist     {
310263efafacSJames Feist         json = nlohmann::json::parse(jsonStream, nullptr, false);
310363efafacSJames Feist         if (json.is_discarded())
310463efafacSJames Feist         {
310563efafacSJames Feist             json = nlohmann::json();
310663efafacSJames Feist         }
310763efafacSJames Feist         jsonStream.close();
310863efafacSJames Feist     }
310963efafacSJames Feist 
311063efafacSJames Feist     std::string typeName;
311163efafacSJames Feist     if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
311263efafacSJames Feist     {
311363efafacSJames Feist         typeName = dimmOffset::dimmPower;
311463efafacSJames Feist     }
311563efafacSJames Feist     else
311663efafacSJames Feist     {
311763efafacSJames Feist         typeName = dimmOffset::staticCltt;
311863efafacSJames Feist     }
311963efafacSJames Feist 
312063efafacSJames Feist     nlohmann::json& field = json[typeName];
312163efafacSJames Feist 
312263efafacSJames Feist     for (const auto& [index, value] : data)
312363efafacSJames Feist     {
312463efafacSJames Feist         field[index] = value;
312563efafacSJames Feist     }
312663efafacSJames Feist 
312763efafacSJames Feist     for (nlohmann::json& val : field)
312863efafacSJames Feist     {
312963efafacSJames Feist         if (val == nullptr)
313063efafacSJames Feist         {
313163efafacSJames Feist             val = static_cast<uint8_t>(0);
313263efafacSJames Feist         }
313363efafacSJames Feist     }
313463efafacSJames Feist 
313563efafacSJames Feist     std::ofstream output(dimmOffsetFile);
313663efafacSJames Feist     if (!output.good())
313763efafacSJames Feist     {
313863efafacSJames Feist         std::cerr << "Error writing json file\n";
313963efafacSJames Feist         return ipmi::responseResponseError();
314063efafacSJames Feist     }
314163efafacSJames Feist 
314263efafacSJames Feist     output << json.dump(4);
314363efafacSJames Feist 
314463efafacSJames Feist     if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
314563efafacSJames Feist     {
314663efafacSJames Feist         std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
314763efafacSJames Feist 
314863efafacSJames Feist         std::variant<std::vector<uint8_t>> offsets =
314963efafacSJames Feist             field.get<std::vector<uint8_t>>();
315063efafacSJames Feist         auto call = bus->new_method_call(
315163efafacSJames Feist             settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
315263efafacSJames Feist         call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
315363efafacSJames Feist         try
315463efafacSJames Feist         {
315563efafacSJames Feist             bus->call(call);
315663efafacSJames Feist         }
315763efafacSJames Feist         catch (sdbusplus::exception_t& e)
315863efafacSJames Feist         {
315963efafacSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
316063efafacSJames Feist                 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
316163efafacSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
316263efafacSJames Feist             return ipmi::responseResponseError();
316363efafacSJames Feist         }
316463efafacSJames Feist     }
316563efafacSJames Feist 
316663efafacSJames Feist     return ipmi::responseSuccess();
316763efafacSJames Feist }
316863efafacSJames Feist 
316963efafacSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
317063efafacSJames Feist {
317163efafacSJames Feist 
317263efafacSJames Feist     if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
317363efafacSJames Feist         type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
317463efafacSJames Feist     {
317563efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
317663efafacSJames Feist     }
317763efafacSJames Feist 
317863efafacSJames Feist     std::ifstream jsonStream(dimmOffsetFile);
317963efafacSJames Feist 
318063efafacSJames Feist     auto json = nlohmann::json::parse(jsonStream, nullptr, false);
318163efafacSJames Feist     if (json.is_discarded())
318263efafacSJames Feist     {
318363efafacSJames Feist         std::cerr << "File error in " << dimmOffsetFile << "\n";
318463efafacSJames Feist         return ipmi::responseResponseError();
318563efafacSJames Feist     }
318663efafacSJames Feist 
318763efafacSJames Feist     std::string typeName;
318863efafacSJames Feist     if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
318963efafacSJames Feist     {
319063efafacSJames Feist         typeName = dimmOffset::dimmPower;
319163efafacSJames Feist     }
319263efafacSJames Feist     else
319363efafacSJames Feist     {
319463efafacSJames Feist         typeName = dimmOffset::staticCltt;
319563efafacSJames Feist     }
319663efafacSJames Feist 
319763efafacSJames Feist     auto it = json.find(typeName);
319863efafacSJames Feist     if (it == json.end())
319963efafacSJames Feist     {
320063efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
320163efafacSJames Feist     }
320263efafacSJames Feist 
320363efafacSJames Feist     if (it->size() <= index)
320463efafacSJames Feist     {
320563efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
320663efafacSJames Feist     }
320763efafacSJames Feist 
320863efafacSJames Feist     uint8_t resp = it->at(index).get<uint8_t>();
320963efafacSJames Feist     return ipmi::responseSuccess(resp);
321063efafacSJames Feist }
321163efafacSJames Feist 
32124f7e76bbSChen,Yugang namespace boot_options
32134f7e76bbSChen,Yugang {
32144f7e76bbSChen,Yugang 
32154f7e76bbSChen,Yugang using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
32164f7e76bbSChen,Yugang using IpmiValue = uint8_t;
32174f7e76bbSChen,Yugang constexpr auto ipmiDefault = 0;
32184f7e76bbSChen,Yugang 
32194f7e76bbSChen,Yugang std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
32204f7e76bbSChen,Yugang     {0x01, Source::Sources::Network},
32214f7e76bbSChen,Yugang     {0x02, Source::Sources::Disk},
32224f7e76bbSChen,Yugang     {0x05, Source::Sources::ExternalMedia},
32234f7e76bbSChen,Yugang     {0x0f, Source::Sources::RemovableMedia},
32244f7e76bbSChen,Yugang     {ipmiDefault, Source::Sources::Default}};
32254f7e76bbSChen,Yugang 
32264f7e76bbSChen,Yugang std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
3227ca12a7beSChen Yugang     {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
32284f7e76bbSChen,Yugang 
32294f7e76bbSChen,Yugang std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
32304f7e76bbSChen,Yugang     {Source::Sources::Network, 0x01},
32314f7e76bbSChen,Yugang     {Source::Sources::Disk, 0x02},
32324f7e76bbSChen,Yugang     {Source::Sources::ExternalMedia, 0x05},
32334f7e76bbSChen,Yugang     {Source::Sources::RemovableMedia, 0x0f},
32344f7e76bbSChen,Yugang     {Source::Sources::Default, ipmiDefault}};
32354f7e76bbSChen,Yugang 
32364f7e76bbSChen,Yugang std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
3237ca12a7beSChen Yugang     {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
32384f7e76bbSChen,Yugang 
32394f7e76bbSChen,Yugang static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
32404f7e76bbSChen,Yugang static constexpr auto bootSourceIntf =
32414f7e76bbSChen,Yugang     "xyz.openbmc_project.Control.Boot.Source";
32424f7e76bbSChen,Yugang static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
32434f7e76bbSChen,Yugang static constexpr auto persistentObjPath =
32444f7e76bbSChen,Yugang     "/xyz/openbmc_project/control/host0/boot";
32454f7e76bbSChen,Yugang static constexpr auto oneTimePath =
32464f7e76bbSChen,Yugang     "/xyz/openbmc_project/control/host0/boot/one_time";
32474f7e76bbSChen,Yugang static constexpr auto bootSourceProp = "BootSource";
32484f7e76bbSChen,Yugang static constexpr auto bootModeProp = "BootMode";
32494f7e76bbSChen,Yugang static constexpr auto oneTimeBootEnableProp = "Enabled";
32504f7e76bbSChen,Yugang static constexpr auto httpBootMode =
32514f7e76bbSChen,Yugang     "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
32524f7e76bbSChen,Yugang 
32534f7e76bbSChen,Yugang enum class BootOptionParameter : size_t
32544f7e76bbSChen,Yugang {
32554f7e76bbSChen,Yugang     setInProgress = 0x0,
32564f7e76bbSChen,Yugang     bootFlags = 0x5,
32574f7e76bbSChen,Yugang };
32584f7e76bbSChen,Yugang static constexpr uint8_t setComplete = 0x0;
32594f7e76bbSChen,Yugang static constexpr uint8_t setInProgress = 0x1;
32604f7e76bbSChen,Yugang static uint8_t transferStatus = setComplete;
32614f7e76bbSChen,Yugang static constexpr uint8_t setParmVersion = 0x01;
32624f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
32634f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
32644f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
32654f7e76bbSChen,Yugang static constexpr uint8_t httpBoot = 0xd;
32664f7e76bbSChen,Yugang static constexpr uint8_t bootSourceMask = 0x3c;
32674f7e76bbSChen,Yugang 
32684f7e76bbSChen,Yugang } // namespace boot_options
32694f7e76bbSChen,Yugang 
32704f7e76bbSChen,Yugang ipmi::RspType<uint8_t,               // version
32714f7e76bbSChen,Yugang               uint8_t,               // param
32724f7e76bbSChen,Yugang               uint8_t,               // data0, dependent on parameter
32734f7e76bbSChen,Yugang               std::optional<uint8_t> // data1, dependent on parameter
32744f7e76bbSChen,Yugang               >
32754f7e76bbSChen,Yugang     ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
32764f7e76bbSChen,Yugang {
32774f7e76bbSChen,Yugang     using namespace boot_options;
32784f7e76bbSChen,Yugang     uint8_t bootOption = 0;
32794f7e76bbSChen,Yugang 
32804f7e76bbSChen,Yugang     if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
32814f7e76bbSChen,Yugang     {
32824f7e76bbSChen,Yugang         return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
32834f7e76bbSChen,Yugang                                      std::nullopt);
32844f7e76bbSChen,Yugang     }
32854f7e76bbSChen,Yugang 
32864f7e76bbSChen,Yugang     if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
32874f7e76bbSChen,Yugang     {
32884f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(
32894f7e76bbSChen,Yugang             "Unsupported parameter");
32904f7e76bbSChen,Yugang         return ipmi::responseResponseError();
32914f7e76bbSChen,Yugang     }
32924f7e76bbSChen,Yugang 
32934f7e76bbSChen,Yugang     try
32944f7e76bbSChen,Yugang     {
32954f7e76bbSChen,Yugang         auto oneTimeEnabled = false;
32964f7e76bbSChen,Yugang         // read one time Enabled property
32974f7e76bbSChen,Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
32984f7e76bbSChen,Yugang         std::string service = getService(*dbus, enabledIntf, oneTimePath);
32994f7e76bbSChen,Yugang         Value variant = getDbusProperty(*dbus, service, oneTimePath,
33004f7e76bbSChen,Yugang                                         enabledIntf, oneTimeBootEnableProp);
33014f7e76bbSChen,Yugang         oneTimeEnabled = std::get<bool>(variant);
33024f7e76bbSChen,Yugang 
33034f7e76bbSChen,Yugang         // get BootSource and BootMode properties
33044f7e76bbSChen,Yugang         // according to oneTimeEnable
33054f7e76bbSChen,Yugang         auto bootObjPath = oneTimePath;
33064f7e76bbSChen,Yugang         if (oneTimeEnabled == false)
33074f7e76bbSChen,Yugang         {
33084f7e76bbSChen,Yugang             bootObjPath = persistentObjPath;
33094f7e76bbSChen,Yugang         }
33104f7e76bbSChen,Yugang 
33114f7e76bbSChen,Yugang         service = getService(*dbus, bootModeIntf, bootObjPath);
33124f7e76bbSChen,Yugang         variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
33134f7e76bbSChen,Yugang                                   bootModeProp);
33144f7e76bbSChen,Yugang 
33154f7e76bbSChen,Yugang         auto bootMode =
33164f7e76bbSChen,Yugang             Mode::convertModesFromString(std::get<std::string>(variant));
33174f7e76bbSChen,Yugang 
33184f7e76bbSChen,Yugang         service = getService(*dbus, bootSourceIntf, bootObjPath);
33194f7e76bbSChen,Yugang         variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
33204f7e76bbSChen,Yugang                                   bootSourceProp);
33214f7e76bbSChen,Yugang 
33224f7e76bbSChen,Yugang         if (std::get<std::string>(variant) == httpBootMode)
33234f7e76bbSChen,Yugang         {
33244f7e76bbSChen,Yugang             bootOption = httpBoot;
33254f7e76bbSChen,Yugang         }
33264f7e76bbSChen,Yugang         else
33274f7e76bbSChen,Yugang         {
33284f7e76bbSChen,Yugang             auto bootSource = Source::convertSourcesFromString(
33294f7e76bbSChen,Yugang                 std::get<std::string>(variant));
33304f7e76bbSChen,Yugang             bootOption = sourceDbusToIpmi.at(bootSource);
33314f7e76bbSChen,Yugang             if (Source::Sources::Default == bootSource)
33324f7e76bbSChen,Yugang             {
33334f7e76bbSChen,Yugang                 bootOption = modeDbusToIpmi.at(bootMode);
33344f7e76bbSChen,Yugang             }
33354f7e76bbSChen,Yugang         }
33364f7e76bbSChen,Yugang 
33374f7e76bbSChen,Yugang         uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
33384f7e76bbSChen,Yugang                                          : setParmBootFlagsValidPermanent;
33394f7e76bbSChen,Yugang         bootOption <<= 2; // shift for responseconstexpr
33404f7e76bbSChen,Yugang         return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
33414f7e76bbSChen,Yugang                                      bootOption);
33424f7e76bbSChen,Yugang     }
33434f7e76bbSChen,Yugang     catch (sdbusplus::exception_t& e)
33444f7e76bbSChen,Yugang     {
33454f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
33464f7e76bbSChen,Yugang         return ipmi::responseResponseError();
33474f7e76bbSChen,Yugang     }
33484f7e76bbSChen,Yugang }
33494f7e76bbSChen,Yugang 
33504f7e76bbSChen,Yugang ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
33514f7e76bbSChen,Yugang                                          std::optional<uint8_t> bootOption)
33524f7e76bbSChen,Yugang {
33534f7e76bbSChen,Yugang     using namespace boot_options;
33544f7e76bbSChen,Yugang     auto oneTimeEnabled = false;
33554f7e76bbSChen,Yugang 
33564f7e76bbSChen,Yugang     if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
33574f7e76bbSChen,Yugang     {
33584f7e76bbSChen,Yugang         if (bootOption)
33594f7e76bbSChen,Yugang         {
33604f7e76bbSChen,Yugang             return ipmi::responseReqDataLenInvalid();
33614f7e76bbSChen,Yugang         }
33624f7e76bbSChen,Yugang 
33634f7e76bbSChen,Yugang         if (transferStatus == setInProgress)
33644f7e76bbSChen,Yugang         {
33654f7e76bbSChen,Yugang             phosphor::logging::log<phosphor::logging::level::ERR>(
33664f7e76bbSChen,Yugang                 "boot option set in progress!");
33674f7e76bbSChen,Yugang             return ipmi::responseResponseError();
33684f7e76bbSChen,Yugang         }
33694f7e76bbSChen,Yugang 
33704f7e76bbSChen,Yugang         transferStatus = bootParam;
33714f7e76bbSChen,Yugang         return ipmi::responseSuccess();
33724f7e76bbSChen,Yugang     }
33734f7e76bbSChen,Yugang 
33744f7e76bbSChen,Yugang     if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
33754f7e76bbSChen,Yugang     {
33764f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(
33774f7e76bbSChen,Yugang             "Unsupported parameter");
33784f7e76bbSChen,Yugang         return ipmi::responseResponseError();
33794f7e76bbSChen,Yugang     }
33804f7e76bbSChen,Yugang 
33814f7e76bbSChen,Yugang     if (!bootOption)
33824f7e76bbSChen,Yugang     {
33834f7e76bbSChen,Yugang         return ipmi::responseReqDataLenInvalid();
33844f7e76bbSChen,Yugang     }
33854f7e76bbSChen,Yugang 
33864f7e76bbSChen,Yugang     if (((bootOption.value() & bootSourceMask) >> 2) !=
33874f7e76bbSChen,Yugang         httpBoot) // not http boot, exit
33884f7e76bbSChen,Yugang     {
33894f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(
33904f7e76bbSChen,Yugang             "wrong boot option parameter!");
33914f7e76bbSChen,Yugang         return ipmi::responseParmOutOfRange();
33924f7e76bbSChen,Yugang     }
33934f7e76bbSChen,Yugang 
33944f7e76bbSChen,Yugang     try
33954f7e76bbSChen,Yugang     {
33964f7e76bbSChen,Yugang         bool permanent = (bootParam & setParmBootFlagsPermanent) ==
33974f7e76bbSChen,Yugang                          setParmBootFlagsPermanent;
33984f7e76bbSChen,Yugang 
33994f7e76bbSChen,Yugang         // read one time Enabled property
34004f7e76bbSChen,Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
34014f7e76bbSChen,Yugang         std::string service = getService(*dbus, enabledIntf, oneTimePath);
34024f7e76bbSChen,Yugang         Value variant = getDbusProperty(*dbus, service, oneTimePath,
34034f7e76bbSChen,Yugang                                         enabledIntf, oneTimeBootEnableProp);
34044f7e76bbSChen,Yugang         oneTimeEnabled = std::get<bool>(variant);
34054f7e76bbSChen,Yugang 
34064f7e76bbSChen,Yugang         /*
34074f7e76bbSChen,Yugang          * Check if the current boot setting is onetime or permanent, if the
34084f7e76bbSChen,Yugang          * request in the command is otherwise, then set the "Enabled"
34094f7e76bbSChen,Yugang          * property in one_time object path to 'True' to indicate onetime
34104f7e76bbSChen,Yugang          * and 'False' to indicate permanent.
34114f7e76bbSChen,Yugang          *
34124f7e76bbSChen,Yugang          * Once the onetime/permanent setting is applied, then the bootMode
34134f7e76bbSChen,Yugang          * and bootSource is updated for the corresponding object.
34144f7e76bbSChen,Yugang          */
34154f7e76bbSChen,Yugang         if (permanent == oneTimeEnabled)
34164f7e76bbSChen,Yugang         {
34174f7e76bbSChen,Yugang             setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
34184f7e76bbSChen,Yugang                             oneTimeBootEnableProp, !permanent);
34194f7e76bbSChen,Yugang         }
34204f7e76bbSChen,Yugang 
34214f7e76bbSChen,Yugang         // set BootSource and BootMode properties
34224f7e76bbSChen,Yugang         // according to oneTimeEnable or persistent
34234f7e76bbSChen,Yugang         auto bootObjPath = oneTimePath;
34244f7e76bbSChen,Yugang         if (oneTimeEnabled == false)
34254f7e76bbSChen,Yugang         {
34264f7e76bbSChen,Yugang             bootObjPath = persistentObjPath;
34274f7e76bbSChen,Yugang         }
34284f7e76bbSChen,Yugang         std::string bootMode =
34294f7e76bbSChen,Yugang             "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
34304f7e76bbSChen,Yugang         std::string bootSource = httpBootMode;
34314f7e76bbSChen,Yugang 
34324f7e76bbSChen,Yugang         service = getService(*dbus, bootModeIntf, bootObjPath);
34334f7e76bbSChen,Yugang         setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
34344f7e76bbSChen,Yugang                         bootMode);
34354f7e76bbSChen,Yugang 
34364f7e76bbSChen,Yugang         service = getService(*dbus, bootSourceIntf, bootObjPath);
34374f7e76bbSChen,Yugang         setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
34384f7e76bbSChen,Yugang                         bootSourceProp, bootSource);
34394f7e76bbSChen,Yugang     }
34404f7e76bbSChen,Yugang     catch (sdbusplus::exception_t& e)
34414f7e76bbSChen,Yugang     {
34424f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
34434f7e76bbSChen,Yugang         return ipmi::responseResponseError();
34444f7e76bbSChen,Yugang     }
34454f7e76bbSChen,Yugang 
34464f7e76bbSChen,Yugang     return ipmi::responseSuccess();
34474f7e76bbSChen,Yugang }
34484f7e76bbSChen,Yugang 
34494e6ee15bSCheng C Yang using BasicVariantType =
34504e6ee15bSCheng C Yang     std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
34514e6ee15bSCheng C Yang                  int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
34524e6ee15bSCheng C Yang                  uint16_t, uint8_t, bool>;
34534e6ee15bSCheng C Yang using PropertyMapType =
34544e6ee15bSCheng C Yang     boost::container::flat_map<std::string, BasicVariantType>;
34554e6ee15bSCheng C Yang static constexpr const std::array<const char*, 1> psuPresenceTypes = {
34564e6ee15bSCheng C Yang     "xyz.openbmc_project.Configuration.PSUPresence"};
34574e6ee15bSCheng C Yang int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
34584e6ee15bSCheng C Yang                   std::vector<uint64_t>& addrTable)
34594e6ee15bSCheng C Yang {
34604e6ee15bSCheng C Yang     boost::system::error_code ec;
34614e6ee15bSCheng C Yang     GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
34624e6ee15bSCheng C Yang         ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
34634e6ee15bSCheng C Yang         "/xyz/openbmc_project/object_mapper",
34644e6ee15bSCheng C Yang         "xyz.openbmc_project.ObjectMapper", "GetSubTree",
34654e6ee15bSCheng C Yang         "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
34664e6ee15bSCheng C Yang     if (ec)
34674e6ee15bSCheng C Yang     {
34684e6ee15bSCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
34694e6ee15bSCheng C Yang             "Failed to set dbus property to cold redundancy");
34704e6ee15bSCheng C Yang         return -1;
34714e6ee15bSCheng C Yang     }
34724e6ee15bSCheng C Yang     for (const auto& object : subtree)
34734e6ee15bSCheng C Yang     {
34744e6ee15bSCheng C Yang         std::string pathName = object.first;
34754e6ee15bSCheng C Yang         for (const auto& serviceIface : object.second)
34764e6ee15bSCheng C Yang         {
34774e6ee15bSCheng C Yang             std::string serviceName = serviceIface.first;
34784e6ee15bSCheng C Yang 
34794e6ee15bSCheng C Yang             ec.clear();
34804e6ee15bSCheng C Yang             PropertyMapType propMap =
34814e6ee15bSCheng C Yang                 ctx->bus->yield_method_call<PropertyMapType>(
34824e6ee15bSCheng C Yang                     ctx->yield, ec, serviceName, pathName,
34834e6ee15bSCheng C Yang                     "org.freedesktop.DBus.Properties", "GetAll",
34844e6ee15bSCheng C Yang                     "xyz.openbmc_project.Configuration.PSUPresence");
34854e6ee15bSCheng C Yang             if (ec)
34864e6ee15bSCheng C Yang             {
34874e6ee15bSCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
34884e6ee15bSCheng C Yang                     "Failed to set dbus property to cold redundancy");
34894e6ee15bSCheng C Yang                 return -1;
34904e6ee15bSCheng C Yang             }
34914e6ee15bSCheng C Yang             auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
34924e6ee15bSCheng C Yang             auto psuAddress =
34934e6ee15bSCheng C Yang                 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
34944e6ee15bSCheng C Yang 
34954e6ee15bSCheng C Yang             if (psuBus == nullptr || psuAddress == nullptr)
34964e6ee15bSCheng C Yang             {
34974e6ee15bSCheng C Yang                 std::cerr << "error finding necessary "
34984e6ee15bSCheng C Yang                              "entry in configuration\n";
34994e6ee15bSCheng C Yang                 return -1;
35004e6ee15bSCheng C Yang             }
35014e6ee15bSCheng C Yang             bus = static_cast<uint8_t>(*psuBus);
35024e6ee15bSCheng C Yang             addrTable = *psuAddress;
35034e6ee15bSCheng C Yang             return 0;
35044e6ee15bSCheng C Yang         }
35054e6ee15bSCheng C Yang     }
35064e6ee15bSCheng C Yang     return -1;
35074e6ee15bSCheng C Yang }
35084e6ee15bSCheng C Yang 
35094e6ee15bSCheng C Yang static const constexpr uint8_t addrOffset = 8;
35104e6ee15bSCheng C Yang static const constexpr uint8_t psuRevision = 0xd9;
35114e6ee15bSCheng C Yang static const constexpr uint8_t defaultPSUBus = 7;
35124e6ee15bSCheng C Yang // Second Minor, Primary Minor, Major
35134e6ee15bSCheng C Yang static const constexpr size_t verLen = 3;
35144e6ee15bSCheng C Yang ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
35154e6ee15bSCheng C Yang {
35164e6ee15bSCheng C Yang     uint8_t bus = defaultPSUBus;
35174e6ee15bSCheng C Yang     std::vector<uint64_t> addrTable;
35184e6ee15bSCheng C Yang     std::vector<uint8_t> result;
35194e6ee15bSCheng C Yang     if (getPSUAddress(ctx, bus, addrTable))
35204e6ee15bSCheng C Yang     {
35214e6ee15bSCheng C Yang         std::cerr << "Failed to get PSU bus and address\n";
35224e6ee15bSCheng C Yang         return ipmi::responseResponseError();
35234e6ee15bSCheng C Yang     }
35244e6ee15bSCheng C Yang 
35254e6ee15bSCheng C Yang     for (const auto& slaveAddr : addrTable)
35264e6ee15bSCheng C Yang     {
35274e6ee15bSCheng C Yang         std::vector<uint8_t> writeData = {psuRevision};
35284e6ee15bSCheng C Yang         std::vector<uint8_t> readBuf(verLen);
35294e6ee15bSCheng C Yang         uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
35304e6ee15bSCheng C Yang         std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
35314e6ee15bSCheng C Yang 
35324e6ee15bSCheng C Yang         auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
35334e6ee15bSCheng C Yang         if (retI2C != ipmi::ccSuccess)
35344e6ee15bSCheng C Yang         {
35354e6ee15bSCheng C Yang             for (size_t idx = 0; idx < verLen; idx++)
35364e6ee15bSCheng C Yang             {
35374e6ee15bSCheng C Yang                 result.emplace_back(0x00);
35384e6ee15bSCheng C Yang             }
35394e6ee15bSCheng C Yang         }
35404e6ee15bSCheng C Yang         else
35414e6ee15bSCheng C Yang         {
35424e6ee15bSCheng C Yang             for (const uint8_t& data : readBuf)
35434e6ee15bSCheng C Yang             {
35444e6ee15bSCheng C Yang                 result.emplace_back(data);
35454e6ee15bSCheng C Yang             }
35464e6ee15bSCheng C Yang         }
35474e6ee15bSCheng C Yang     }
35484e6ee15bSCheng C Yang 
35494e6ee15bSCheng C Yang     return ipmi::responseSuccess(result);
35504e6ee15bSCheng C Yang }
35514e6ee15bSCheng C Yang 
35522030d7c8Ssrikanta mondal std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
35532030d7c8Ssrikanta mondal                                                 const std::string& name)
35542030d7c8Ssrikanta mondal {
35552030d7c8Ssrikanta mondal     Value dbusValue = 0;
35562030d7c8Ssrikanta mondal     std::string serviceName;
35572030d7c8Ssrikanta mondal 
35582030d7c8Ssrikanta mondal     boost::system::error_code ec =
35592030d7c8Ssrikanta mondal         ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
35602030d7c8Ssrikanta mondal 
35612030d7c8Ssrikanta mondal     if (ec)
35622030d7c8Ssrikanta mondal     {
35632030d7c8Ssrikanta mondal         phosphor::logging::log<phosphor::logging::level::ERR>(
35642030d7c8Ssrikanta mondal             "Failed to perform Multinode getService.");
35652030d7c8Ssrikanta mondal         return std::nullopt;
35662030d7c8Ssrikanta mondal     }
35672030d7c8Ssrikanta mondal 
35682030d7c8Ssrikanta mondal     ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
35692030d7c8Ssrikanta mondal                                multiNodeIntf, name, dbusValue);
35702030d7c8Ssrikanta mondal     if (ec)
35712030d7c8Ssrikanta mondal     {
35722030d7c8Ssrikanta mondal         phosphor::logging::log<phosphor::logging::level::ERR>(
35732030d7c8Ssrikanta mondal             "Failed to perform Multinode get property");
35742030d7c8Ssrikanta mondal         return std::nullopt;
35752030d7c8Ssrikanta mondal     }
35762030d7c8Ssrikanta mondal 
35772030d7c8Ssrikanta mondal     auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
35782030d7c8Ssrikanta mondal     if (!multiNodeVal)
35792030d7c8Ssrikanta mondal     {
35802030d7c8Ssrikanta mondal         phosphor::logging::log<phosphor::logging::level::ERR>(
35812030d7c8Ssrikanta mondal             "getMultiNodeInfoPresence: error to get multinode");
35822030d7c8Ssrikanta mondal         return std::nullopt;
35832030d7c8Ssrikanta mondal     }
35842030d7c8Ssrikanta mondal     return *multiNodeVal;
35852030d7c8Ssrikanta mondal }
35862030d7c8Ssrikanta mondal 
35872030d7c8Ssrikanta mondal /** @brief implements OEM get reading command
35882030d7c8Ssrikanta mondal  *  @param domain ID
35892030d7c8Ssrikanta mondal  *  @param reading Type
35902030d7c8Ssrikanta mondal  *    - 00h = platform Power Consumption
35912030d7c8Ssrikanta mondal  *    - 01h = inlet Air Temp
35922030d7c8Ssrikanta mondal  *    - 02h = icc_TDC from PECI
35932030d7c8Ssrikanta mondal  *  @param reserved, write as 0000h
35942030d7c8Ssrikanta mondal  *
35952030d7c8Ssrikanta mondal  *  @returns IPMI completion code plus response data
35962030d7c8Ssrikanta mondal  *  - response
35972030d7c8Ssrikanta mondal  *     - domain ID
35982030d7c8Ssrikanta mondal  *     - reading Type
35992030d7c8Ssrikanta mondal  *       - 00h = platform Power Consumption
36002030d7c8Ssrikanta mondal  *       - 01h = inlet Air Temp
36012030d7c8Ssrikanta mondal  *       - 02h = icc_TDC from PECI
36022030d7c8Ssrikanta mondal  *     - reading
36032030d7c8Ssrikanta mondal  */
36042030d7c8Ssrikanta mondal ipmi::RspType<uint4_t, // domain ID
36052030d7c8Ssrikanta mondal               uint4_t, // reading Type
36062030d7c8Ssrikanta mondal               uint16_t // reading Value
36072030d7c8Ssrikanta mondal               >
36082030d7c8Ssrikanta mondal     ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
36092030d7c8Ssrikanta mondal                       uint4_t readingType, uint16_t reserved)
36102030d7c8Ssrikanta mondal {
36112030d7c8Ssrikanta mondal     constexpr uint8_t platformPower = 0;
36122030d7c8Ssrikanta mondal     constexpr uint8_t inletAirTemp = 1;
36132030d7c8Ssrikanta mondal     constexpr uint8_t iccTdc = 2;
36142030d7c8Ssrikanta mondal 
36152030d7c8Ssrikanta mondal     if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
36162030d7c8Ssrikanta mondal     {
36172030d7c8Ssrikanta mondal         return ipmi::responseInvalidFieldRequest();
36182030d7c8Ssrikanta mondal     }
36192030d7c8Ssrikanta mondal 
36202030d7c8Ssrikanta mondal     // This command should run only from multi-node product.
36212030d7c8Ssrikanta mondal     // For all other platforms this command will return invalid.
36222030d7c8Ssrikanta mondal 
36232030d7c8Ssrikanta mondal     std::optional<uint8_t> nodeInfo =
36242030d7c8Ssrikanta mondal         getMultiNodeInfoPresence(ctx, "NodePresence");
36252030d7c8Ssrikanta mondal     if (!nodeInfo || !*nodeInfo)
36262030d7c8Ssrikanta mondal     {
36272030d7c8Ssrikanta mondal         return ipmi::responseInvalidCommand();
36282030d7c8Ssrikanta mondal     }
36292030d7c8Ssrikanta mondal 
36302030d7c8Ssrikanta mondal     uint16_t oemReadingValue = 0;
36312030d7c8Ssrikanta mondal     if (static_cast<uint8_t>(readingType) == inletAirTemp)
36322030d7c8Ssrikanta mondal     {
36332030d7c8Ssrikanta mondal         double value = 0;
36342030d7c8Ssrikanta mondal         boost::system::error_code ec = ipmi::getDbusProperty(
36352030d7c8Ssrikanta mondal             ctx, "xyz.openbmc_project.HwmonTempSensor",
36362030d7c8Ssrikanta mondal             "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
36372030d7c8Ssrikanta mondal             "xyz.openbmc_project.Sensor.Value", "Value", value);
36382030d7c8Ssrikanta mondal         if (ec)
36392030d7c8Ssrikanta mondal         {
36402030d7c8Ssrikanta mondal             phosphor::logging::log<phosphor::logging::level::ERR>(
36412030d7c8Ssrikanta mondal                 "Failed to get BMC Get OEM temperature",
36422030d7c8Ssrikanta mondal                 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
36432030d7c8Ssrikanta mondal             return ipmi::responseUnspecifiedError();
36442030d7c8Ssrikanta mondal         }
36452030d7c8Ssrikanta mondal         // Take the Inlet temperature
36462030d7c8Ssrikanta mondal         oemReadingValue = static_cast<uint16_t>(value);
36472030d7c8Ssrikanta mondal     }
36482030d7c8Ssrikanta mondal     else
36492030d7c8Ssrikanta mondal     {
36502030d7c8Ssrikanta mondal         phosphor::logging::log<phosphor::logging::level::ERR>(
36512030d7c8Ssrikanta mondal             "Currently Get OEM Reading support only for Inlet Air Temp");
36522030d7c8Ssrikanta mondal         return ipmi::responseParmOutOfRange();
36532030d7c8Ssrikanta mondal     }
36542030d7c8Ssrikanta mondal     return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
36552030d7c8Ssrikanta mondal }
36562030d7c8Ssrikanta mondal 
365728972063SAppaRao Puli /** @brief implements the maximum size of
365828972063SAppaRao Puli  *  bridgeable messages used between KCS and
365928972063SAppaRao Puli  *  IPMB interfacesget security mode command.
366028972063SAppaRao Puli  *
366128972063SAppaRao Puli  *  @returns IPMI completion code with following data
366228972063SAppaRao Puli  *   - KCS Buffer Size (In multiples of four bytes)
366328972063SAppaRao Puli  *   - IPMB Buffer Size (In multiples of four bytes)
366428972063SAppaRao Puli  **/
366528972063SAppaRao Puli ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
366628972063SAppaRao Puli {
366728972063SAppaRao Puli     // for now this is hard coded; really this number is dependent on
366828972063SAppaRao Puli     // the BMC kcs driver as well as the host kcs driver....
366928972063SAppaRao Puli     // we can't know the latter.
367028972063SAppaRao Puli     uint8_t kcsMaxBufferSize = 63 / 4;
367128972063SAppaRao Puli     uint8_t ipmbMaxBufferSize = 128 / 4;
367228972063SAppaRao Puli 
367328972063SAppaRao Puli     return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
367428972063SAppaRao Puli }
367528972063SAppaRao Puli 
367664796041SJason M. Bills static void registerOEMFunctions(void)
3677a835eaa0SJia, Chunhui {
3678a835eaa0SJia, Chunhui     phosphor::logging::log<phosphor::logging::level::INFO>(
3679a835eaa0SJia, Chunhui         "Registering OEM commands");
368098bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
368198bbf69aSVernon Mauery                          intel::general::cmdGetChassisIdentifier, NULL,
368298bbf69aSVernon Mauery                          ipmiOEMGetChassisIdentifier,
3683a835eaa0SJia, Chunhui                          PRIVILEGE_USER); // get chassis identifier
368498bbf69aSVernon Mauery 
368598bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
368664796041SJason M. Bills                          NULL, ipmiOEMSetSystemGUID,
3687a835eaa0SJia, Chunhui                          PRIVILEGE_ADMIN); // set system guid
3688b02bf095SJason M. Bills 
3689b02bf095SJason M. Bills     // <Disable BMC System Reset Action>
369098bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
369198bbf69aSVernon Mauery                     intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
369298bbf69aSVernon Mauery                     ipmiOEMDisableBMCSystemReset);
369398bbf69aSVernon Mauery 
3694b02bf095SJason M. Bills     // <Get BMC Reset Disables>
369598bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
369698bbf69aSVernon Mauery                     intel::general::cmdGetBMCResetDisables, Privilege::Admin,
369798bbf69aSVernon Mauery                     ipmiOEMGetBMCResetDisables);
3698b02bf095SJason M. Bills 
369998bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
370064796041SJason M. Bills                          NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
3701cc49b54bSJia, Chunhui 
37027a04f3a4SChen Yugang     registerHandler(prioOemBase, intel::netFnGeneral,
37037a04f3a4SChen Yugang                     intel::general::cmdGetOEMDeviceInfo, Privilege::User,
37047a04f3a4SChen Yugang                     ipmiOEMGetDeviceInfo);
3705cc49b54bSJia, Chunhui 
370698bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
370798bbf69aSVernon Mauery                          intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
370898bbf69aSVernon Mauery                          ipmiOEMGetAICFRU, PRIVILEGE_USER);
3709d509eb91SSuryakanth Sekar 
371098bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
371198bbf69aSVernon Mauery                     intel::general::cmdSendEmbeddedFWUpdStatus,
371298bbf69aSVernon Mauery                     Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
3713d509eb91SSuryakanth Sekar 
37142b664d5aSRajashekar Gade Reddy     registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
37152b664d5aSRajashekar Gade Reddy                     Privilege::Admin, ipmiOEMSlotIpmb);
37162b664d5aSRajashekar Gade Reddy 
371798bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
371898bbf69aSVernon Mauery                          intel::general::cmdSetPowerRestoreDelay, NULL,
371998bbf69aSVernon Mauery                          ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
372098bbf69aSVernon Mauery 
372198bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
372298bbf69aSVernon Mauery                          intel::general::cmdGetPowerRestoreDelay, NULL,
372398bbf69aSVernon Mauery                          ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
372498bbf69aSVernon Mauery 
372598bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
372698bbf69aSVernon Mauery                     intel::general::cmdSetOEMUser2Activation,
372798bbf69aSVernon Mauery                     Privilege::Callback, ipmiOEMSetUser2Activation);
372898bbf69aSVernon Mauery 
372998bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
373098bbf69aSVernon Mauery                     intel::general::cmdSetSpecialUserPassword,
373198bbf69aSVernon Mauery                     Privilege::Callback, ipmiOEMSetSpecialUserPassword);
3732fc5e985bSRichard Marian Thomaiyar 
373342bd9c8eSJason M. Bills     // <Get Processor Error Config>
373498bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
373598bbf69aSVernon Mauery                     intel::general::cmdGetProcessorErrConfig, Privilege::User,
373698bbf69aSVernon Mauery                     ipmiOEMGetProcessorErrConfig);
373798bbf69aSVernon Mauery 
373842bd9c8eSJason M. Bills     // <Set Processor Error Config>
373998bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
374098bbf69aSVernon Mauery                     intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
374198bbf69aSVernon Mauery                     ipmiOEMSetProcessorErrConfig);
374242bd9c8eSJason M. Bills 
374398bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
374498bbf69aSVernon Mauery                          intel::general::cmdSetShutdownPolicy, NULL,
374598bbf69aSVernon Mauery                          ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
374691244a6aSJames Feist 
374798bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
374898bbf69aSVernon Mauery                          intel::general::cmdGetShutdownPolicy, NULL,
374998bbf69aSVernon Mauery                          ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
375098bbf69aSVernon Mauery 
3751f945eee0Sanil kumar appana     registerHandler(prioOemBase, intel::netFnGeneral,
3752f945eee0Sanil kumar appana                     intel::general::cmdSetFanConfig, Privilege::User,
3753f945eee0Sanil kumar appana                     ipmiOEMSetFanConfig);
375491244a6aSJames Feist 
375598bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
375698bbf69aSVernon Mauery                     intel::general::cmdGetFanConfig, Privilege::User,
375798bbf69aSVernon Mauery                     ipmiOEMGetFanConfig);
375891244a6aSJames Feist 
375998bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
376098bbf69aSVernon Mauery                     intel::general::cmdGetFanSpeedOffset, Privilege::User,
376198bbf69aSVernon Mauery                     ipmiOEMGetFanSpeedOffset);
37625f957cafSJames Feist 
376398bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
376498bbf69aSVernon Mauery                     intel::general::cmdSetFanSpeedOffset, Privilege::User,
376598bbf69aSVernon Mauery                     ipmiOEMSetFanSpeedOffset);
3766acc8a4ebSJames Feist 
376798bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
376898bbf69aSVernon Mauery                     intel::general::cmdSetFscParameter, Privilege::User,
376998bbf69aSVernon Mauery                     ipmiOEMSetFscParameter);
3770acc8a4ebSJames Feist 
377198bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
377298bbf69aSVernon Mauery                     intel::general::cmdGetFscParameter, Privilege::User,
377398bbf69aSVernon Mauery                     ipmiOEMGetFscParameter);
37745f957cafSJames Feist 
377598bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
377698bbf69aSVernon Mauery                     intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
377798bbf69aSVernon Mauery                     ipmiOEMReadBoardProductId);
3778ea537d53SRichard Marian Thomaiyar 
377998bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
378098bbf69aSVernon Mauery                     intel::general::cmdGetNmiStatus, Privilege::User,
378198bbf69aSVernon Mauery                     ipmiOEMGetNmiSource);
378239736d59SChen Yugang 
378398bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
378498bbf69aSVernon Mauery                     intel::general::cmdSetNmiStatus, Privilege::Operator,
378598bbf69aSVernon Mauery                     ipmiOEMSetNmiSource);
378639736d59SChen Yugang 
378798bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
378898bbf69aSVernon Mauery                     intel::general::cmdGetEfiBootOptions, Privilege::User,
378998bbf69aSVernon Mauery                     ipmiOemGetEfiBootOptions);
37904f7e76bbSChen,Yugang 
379198bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
379298bbf69aSVernon Mauery                     intel::general::cmdSetEfiBootOptions, Privilege::Operator,
379398bbf69aSVernon Mauery                     ipmiOemSetEfiBootOptions);
37944f7e76bbSChen,Yugang 
379598bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
379698bbf69aSVernon Mauery                     intel::general::cmdGetSecurityMode, Privilege::User,
379798bbf69aSVernon Mauery                     ipmiGetSecurityMode);
3798d801e463SRichard Marian Thomaiyar 
379998bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
380098bbf69aSVernon Mauery                     intel::general::cmdSetSecurityMode, Privilege::Admin,
380198bbf69aSVernon Mauery                     ipmiSetSecurityMode);
3802d801e463SRichard Marian Thomaiyar 
3803abd11ca3SNITIN SHARMA     registerHandler(prioOemBase, intel::netFnGeneral,
3804abd11ca3SNITIN SHARMA                     intel::general::cmdGetLEDStatus, Privilege::Admin,
3805abd11ca3SNITIN SHARMA                     ipmiOEMGetLEDStatus);
38064ac799d7SVernon Mauery 
380798bbf69aSVernon Mauery     ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
380898bbf69aSVernon Mauery                          ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
380998bbf69aSVernon Mauery                          ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3810773703a5SCheng C Yang 
381198bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
381298bbf69aSVernon Mauery                     intel::general::cmdSetFaultIndication, Privilege::Operator,
381398bbf69aSVernon Mauery                     ipmiOEMSetFaultIndication);
381498bbf69aSVernon Mauery 
381598bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
381698bbf69aSVernon Mauery                     intel::general::cmdSetColdRedundancyConfig, Privilege::User,
381798bbf69aSVernon Mauery                     ipmiOEMSetCRConfig);
381898bbf69aSVernon Mauery 
381998bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
382098bbf69aSVernon Mauery                     intel::general::cmdGetColdRedundancyConfig, Privilege::User,
382198bbf69aSVernon Mauery                     ipmiOEMGetCRConfig);
382298bbf69aSVernon Mauery 
382398bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
382498bbf69aSVernon Mauery                     intel::general::cmdRestoreConfiguration, Privilege::Admin,
38254ac799d7SVernon Mauery                     ipmiRestoreConfiguration);
382663efafacSJames Feist 
382798bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
382898bbf69aSVernon Mauery                     intel::general::cmdSetDimmOffset, Privilege::Operator,
382998bbf69aSVernon Mauery                     ipmiOEMSetDimmOffset);
383063efafacSJames Feist 
383198bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
383298bbf69aSVernon Mauery                     intel::general::cmdGetDimmOffset, Privilege::Operator,
383398bbf69aSVernon Mauery                     ipmiOEMGetDimmOffset);
3834ca12a7beSChen Yugang 
38354e6ee15bSCheng C Yang     registerHandler(prioOemBase, intel::netFnGeneral,
38364e6ee15bSCheng C Yang                     intel::general::cmdGetPSUVersion, Privilege::User,
38374e6ee15bSCheng C Yang                     ipmiOEMGetPSUVersion);
383828972063SAppaRao Puli 
383928972063SAppaRao Puli     registerHandler(prioOemBase, intel::netFnGeneral,
384028972063SAppaRao Puli                     intel::general::cmdGetBufferSize, Privilege::User,
384128972063SAppaRao Puli                     ipmiOEMGetBufferSize);
38422030d7c8Ssrikanta mondal 
38432030d7c8Ssrikanta mondal     registerHandler(prioOemBase, intel::netFnGeneral,
38442030d7c8Ssrikanta mondal                     intel::general::cmdOEMGetReading, Privilege::User,
38452030d7c8Ssrikanta mondal                     ipmiOEMGetReading);
3846a835eaa0SJia, Chunhui }
3847a835eaa0SJia, Chunhui 
3848a835eaa0SJia, Chunhui } // namespace ipmi
3849