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 
1764796041SJason M. Bills #include "xyz/openbmc_project/Common/error.hpp"
1845f04988SKuiying Wang #include "xyz/openbmc_project/Led/Physical/server.hpp"
1964796041SJason M. Bills 
20cc49b54bSJia, Chunhui #include <systemd/sd-journal.h>
21a835eaa0SJia, Chunhui 
22a835eaa0SJia, Chunhui #include <array>
2391244a6aSJames Feist #include <boost/container/flat_map.hpp>
2423737fe3SYong Li #include <boost/process/child.hpp>
2523737fe3SYong Li #include <boost/process/io.hpp>
2639736d59SChen Yugang #include <com/intel/Control/NMISource/server.hpp>
270669d193SYong Li #include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
2864796041SJason M. Bills #include <commandutils.hpp>
294ac799d7SVernon Mauery #include <filesystem>
30a835eaa0SJia, Chunhui #include <iostream>
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>
38a835eaa0SJia, Chunhui #include <string>
3991244a6aSJames Feist #include <variant>
40a835eaa0SJia, Chunhui #include <vector>
414f7e76bbSChen,Yugang #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
424f7e76bbSChen,Yugang #include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
43773703a5SCheng C Yang #include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
44d801e463SRichard Marian Thomaiyar #include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
45a835eaa0SJia, Chunhui 
46a835eaa0SJia, Chunhui namespace ipmi
47a835eaa0SJia, Chunhui {
4864796041SJason M. Bills static void registerOEMFunctions() __attribute__((constructor));
494ac799d7SVernon Mauery 
5064796041SJason M. Bills static constexpr size_t maxFRUStringLength = 0x3F;
51a835eaa0SJia, Chunhui 
52d509eb91SSuryakanth Sekar static constexpr auto ethernetIntf =
53d509eb91SSuryakanth Sekar     "xyz.openbmc_project.Network.EthernetInterface";
54d509eb91SSuryakanth Sekar static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
55d509eb91SSuryakanth Sekar static constexpr auto networkService = "xyz.openbmc_project.Network";
56d509eb91SSuryakanth Sekar static constexpr auto networkRoot = "/xyz/openbmc_project/network";
57d509eb91SSuryakanth Sekar 
5839736d59SChen Yugang static constexpr const char* oemNmiSourceIntf = "com.intel.Control.NMISource";
5939736d59SChen Yugang static constexpr const char* oemNmiSourceObjPath =
6039736d59SChen Yugang     "/com/intel/control/NMISource";
6139736d59SChen Yugang static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
6239736d59SChen Yugang static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
6339736d59SChen Yugang 
6463efafacSJames Feist static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
6563efafacSJames Feist 
6639736d59SChen Yugang enum class NmiSource : uint8_t
6739736d59SChen Yugang {
6839736d59SChen Yugang     none = 0,
6939736d59SChen Yugang     fpBtn = 1,
7039736d59SChen Yugang     wdPreTimeout = 2,
7139736d59SChen Yugang     pefMatch = 3,
7239736d59SChen Yugang     chassisCmd = 4,
7339736d59SChen Yugang     memoryError = 5,
7439736d59SChen Yugang     pciSerrPerr = 6,
7539736d59SChen Yugang     southbridgeNmi = 7,
7639736d59SChen Yugang     chipsetNmi = 8,
7739736d59SChen Yugang };
7839736d59SChen Yugang 
79d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeService =
80d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.RestrictionMode.Manager";
81d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeBasePath =
82d801e463SRichard Marian Thomaiyar     "/xyz/openbmc_project/control/security/restriction_mode";
83d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeIntf =
84d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.Control.Security.RestrictionMode";
85d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeProperty = "RestrictionMode";
86d801e463SRichard Marian Thomaiyar 
87d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeService =
88d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.SpecialMode";
89d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeBasePath =
90*a7b74288SRichard Marian Thomaiyar     "/xyz/openbmc_project/security/special_mode";
91d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeIntf =
92d801e463SRichard Marian Thomaiyar     "xyz.openbmc_project.Security.SpecialMode";
93d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeProperty = "SpecialMode";
94d801e463SRichard Marian Thomaiyar 
95d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertyIntf =
96d801e463SRichard Marian Thomaiyar     "org.freedesktop.DBus.Properties";
97d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertyGetMethod = "Get";
98d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertySetMethod = "Set";
99d801e463SRichard Marian Thomaiyar 
100a835eaa0SJia, Chunhui // return code: 0 successful
101a835eaa0SJia, Chunhui int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
102a835eaa0SJia, Chunhui {
103a835eaa0SJia, Chunhui     std::string objpath = "/xyz/openbmc_project/FruDevice";
104a835eaa0SJia, Chunhui     std::string intf = "xyz.openbmc_project.FruDeviceManager";
105a835eaa0SJia, Chunhui     std::string service = getService(bus, intf, objpath);
106a835eaa0SJia, Chunhui     ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
107a835eaa0SJia, Chunhui     if (valueTree.empty())
108a835eaa0SJia, Chunhui     {
109a835eaa0SJia, Chunhui         phosphor::logging::log<phosphor::logging::level::ERR>(
110a835eaa0SJia, Chunhui             "No object implements interface",
111a835eaa0SJia, Chunhui             phosphor::logging::entry("INTF=%s", intf.c_str()));
112a835eaa0SJia, Chunhui         return -1;
113a835eaa0SJia, Chunhui     }
114a835eaa0SJia, Chunhui 
11564796041SJason M. Bills     for (const auto& item : valueTree)
116a835eaa0SJia, Chunhui     {
117a835eaa0SJia, Chunhui         auto interface = item.second.find("xyz.openbmc_project.FruDevice");
118a835eaa0SJia, Chunhui         if (interface == item.second.end())
119a835eaa0SJia, Chunhui         {
120a835eaa0SJia, Chunhui             continue;
121a835eaa0SJia, Chunhui         }
122a835eaa0SJia, Chunhui 
123a835eaa0SJia, Chunhui         auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
124a835eaa0SJia, Chunhui         if (property == interface->second.end())
125a835eaa0SJia, Chunhui         {
126a835eaa0SJia, Chunhui             continue;
127a835eaa0SJia, Chunhui         }
128a835eaa0SJia, Chunhui 
129a835eaa0SJia, Chunhui         try
130a835eaa0SJia, Chunhui         {
131a835eaa0SJia, Chunhui             Value variant = property->second;
1328166c8d7SVernon Mauery             std::string& result = std::get<std::string>(variant);
13364796041SJason M. Bills             if (result.size() > maxFRUStringLength)
134a835eaa0SJia, Chunhui             {
135a835eaa0SJia, Chunhui                 phosphor::logging::log<phosphor::logging::level::ERR>(
136a835eaa0SJia, Chunhui                     "FRU serial number exceed maximum length");
137a835eaa0SJia, Chunhui                 return -1;
138a835eaa0SJia, Chunhui             }
139a835eaa0SJia, Chunhui             serial = result;
140a835eaa0SJia, Chunhui             return 0;
141a835eaa0SJia, Chunhui         }
1428166c8d7SVernon Mauery         catch (std::bad_variant_access& e)
143a835eaa0SJia, Chunhui         {
14464796041SJason M. Bills             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
145a835eaa0SJia, Chunhui             return -1;
146a835eaa0SJia, Chunhui         }
147a835eaa0SJia, Chunhui     }
148a835eaa0SJia, Chunhui     return -1;
149a835eaa0SJia, Chunhui }
15064796041SJason M. Bills 
151a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
152a835eaa0SJia, Chunhui                            ipmi_request_t request, ipmi_response_t response,
15364796041SJason M. Bills                            ipmi_data_len_t dataLen, ipmi_context_t context)
154a835eaa0SJia, Chunhui {
15564796041SJason M. Bills     printCommand(+netfn, +cmd);
156a835eaa0SJia, Chunhui     // Status code.
157a835eaa0SJia, Chunhui     ipmi_ret_t rc = IPMI_CC_INVALID;
15864796041SJason M. Bills     *dataLen = 0;
159a835eaa0SJia, Chunhui     return rc;
160a835eaa0SJia, Chunhui }
161a835eaa0SJia, Chunhui 
162a835eaa0SJia, Chunhui // Returns the Chassis Identifier (serial #)
163a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
164a835eaa0SJia, Chunhui                                        ipmi_request_t request,
165a835eaa0SJia, Chunhui                                        ipmi_response_t response,
16664796041SJason M. Bills                                        ipmi_data_len_t dataLen,
167a835eaa0SJia, Chunhui                                        ipmi_context_t context)
168a835eaa0SJia, Chunhui {
169a835eaa0SJia, Chunhui     std::string serial;
17064796041SJason M. Bills     if (*dataLen != 0) // invalid request if there are extra parameters
171a835eaa0SJia, Chunhui     {
17264796041SJason M. Bills         *dataLen = 0;
173a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
174a835eaa0SJia, Chunhui     }
17515419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
17615419dd5SVernon Mauery     if (getChassisSerialNumber(*dbus, serial) == 0)
177a835eaa0SJia, Chunhui     {
17864796041SJason M. Bills         *dataLen = serial.size(); // length will never exceed response length
179a835eaa0SJia, Chunhui                                   // as it is checked in getChassisSerialNumber
180a835eaa0SJia, Chunhui         char* resp = static_cast<char*>(response);
18164796041SJason M. Bills         serial.copy(resp, *dataLen);
182a835eaa0SJia, Chunhui         return IPMI_CC_OK;
183a835eaa0SJia, Chunhui     }
18464796041SJason M. Bills     *dataLen = 0;
185a835eaa0SJia, Chunhui     return IPMI_CC_RESPONSE_ERROR;
186a835eaa0SJia, Chunhui }
187a835eaa0SJia, Chunhui 
188a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
189a835eaa0SJia, Chunhui                                 ipmi_request_t request,
190a835eaa0SJia, Chunhui                                 ipmi_response_t response,
19164796041SJason M. Bills                                 ipmi_data_len_t dataLen, ipmi_context_t context)
192a835eaa0SJia, Chunhui {
193a835eaa0SJia, Chunhui     static constexpr size_t safeBufferLength = 50;
194a835eaa0SJia, Chunhui     char buf[safeBufferLength] = {0};
195a835eaa0SJia, Chunhui     GUIDData* Data = reinterpret_cast<GUIDData*>(request);
196a835eaa0SJia, Chunhui 
19764796041SJason M. Bills     if (*dataLen != sizeof(GUIDData)) // 16bytes
198a835eaa0SJia, Chunhui     {
19964796041SJason M. Bills         *dataLen = 0;
200a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
201a835eaa0SJia, Chunhui     }
202a835eaa0SJia, Chunhui 
20364796041SJason M. Bills     *dataLen = 0;
204a835eaa0SJia, Chunhui 
205a835eaa0SJia, Chunhui     snprintf(
206a835eaa0SJia, Chunhui         buf, safeBufferLength,
207a835eaa0SJia, Chunhui         "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
208a835eaa0SJia, Chunhui         Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
209a835eaa0SJia, Chunhui         Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
210a835eaa0SJia, Chunhui         Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
211a835eaa0SJia, Chunhui         Data->node3, Data->node2, Data->node1);
212a835eaa0SJia, Chunhui     // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
213a835eaa0SJia, Chunhui     std::string guid = buf;
214a835eaa0SJia, Chunhui 
215a835eaa0SJia, Chunhui     std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
216a835eaa0SJia, Chunhui     std::string intf = "xyz.openbmc_project.Common.UUID";
21715419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
21815419dd5SVernon Mauery     std::string service = getService(*dbus, intf, objpath);
21915419dd5SVernon Mauery     setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
220a835eaa0SJia, Chunhui     return IPMI_CC_OK;
221a835eaa0SJia, Chunhui }
222a835eaa0SJia, Chunhui 
223b02bf095SJason M. Bills ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
224b02bf095SJason M. Bills                                              uint7_t reserved1)
225b02bf095SJason M. Bills {
226b02bf095SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
227b02bf095SJason M. Bills 
228b02bf095SJason M. Bills     try
229b02bf095SJason M. Bills     {
230b02bf095SJason M. Bills         auto service =
231b02bf095SJason M. Bills             ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
232b02bf095SJason M. Bills         ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
233b02bf095SJason M. Bills                               bmcResetDisablesIntf, "ResetOnSMI",
234b02bf095SJason M. Bills                               !disableResetOnSMI);
235b02bf095SJason M. Bills     }
236b02bf095SJason M. Bills     catch (std::exception& e)
237b02bf095SJason M. Bills     {
238b02bf095SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
239b02bf095SJason M. Bills             "Failed to set BMC reset disables",
240b02bf095SJason M. Bills             phosphor::logging::entry("EXCEPTION=%s", e.what()));
241b02bf095SJason M. Bills         return ipmi::responseUnspecifiedError();
242b02bf095SJason M. Bills     }
243b02bf095SJason M. Bills 
244b02bf095SJason M. Bills     return ipmi::responseSuccess();
245b02bf095SJason M. Bills }
246b02bf095SJason M. Bills 
247b02bf095SJason M. Bills ipmi::RspType<bool,   // disableResetOnSMI
248b02bf095SJason M. Bills               uint7_t // reserved
249b02bf095SJason M. Bills               >
250b02bf095SJason M. Bills     ipmiOEMGetBMCResetDisables()
251b02bf095SJason M. Bills {
252b02bf095SJason M. Bills     bool disableResetOnSMI = true;
253b02bf095SJason M. Bills 
254b02bf095SJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
255b02bf095SJason M. Bills     try
256b02bf095SJason M. Bills     {
257b02bf095SJason M. Bills         auto service =
258b02bf095SJason M. Bills             ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
259b02bf095SJason M. Bills         Value variant =
260b02bf095SJason M. Bills             ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
261b02bf095SJason M. Bills                                   bmcResetDisablesIntf, "ResetOnSMI");
262b02bf095SJason M. Bills         disableResetOnSMI = !std::get<bool>(variant);
263b02bf095SJason M. Bills     }
264b02bf095SJason M. Bills     catch (std::exception& e)
265b02bf095SJason M. Bills     {
266b02bf095SJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
267b02bf095SJason M. Bills             "Failed to get BMC reset disables",
268b02bf095SJason M. Bills             phosphor::logging::entry("EXCEPTION=%s", e.what()));
269b02bf095SJason M. Bills         return ipmi::responseUnspecifiedError();
270b02bf095SJason M. Bills     }
271b02bf095SJason M. Bills 
272b02bf095SJason M. Bills     return ipmi::responseSuccess(disableResetOnSMI, 0);
273b02bf095SJason M. Bills }
274b02bf095SJason M. Bills 
275a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
276a835eaa0SJia, Chunhui                             ipmi_request_t request, ipmi_response_t response,
277a835eaa0SJia, Chunhui                             ipmi_data_len_t dataLen, ipmi_context_t context)
278a835eaa0SJia, Chunhui {
279a835eaa0SJia, Chunhui     DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
280a835eaa0SJia, Chunhui 
28164796041SJason M. Bills     if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
282a835eaa0SJia, Chunhui     {
283a835eaa0SJia, Chunhui         *dataLen = 0;
284a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
285a835eaa0SJia, Chunhui     }
28664796041SJason M. Bills     std::string idString((char*)data->biosId, data->biosIDLength);
287a835eaa0SJia, Chunhui 
28815419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
28915419dd5SVernon Mauery     std::string service = getService(*dbus, biosIntf, biosObjPath);
29015419dd5SVernon Mauery     setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
291a835eaa0SJia, Chunhui     uint8_t* bytesWritten = static_cast<uint8_t*>(response);
292a835eaa0SJia, Chunhui     *bytesWritten =
29364796041SJason M. Bills         data->biosIDLength; // how many bytes are written into storage
294a835eaa0SJia, Chunhui     *dataLen = 1;
295a835eaa0SJia, Chunhui     return IPMI_CC_OK;
296a835eaa0SJia, Chunhui }
297a835eaa0SJia, Chunhui 
298a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
299a835eaa0SJia, Chunhui                                 ipmi_request_t request,
300a835eaa0SJia, Chunhui                                 ipmi_response_t response,
301a835eaa0SJia, Chunhui                                 ipmi_data_len_t dataLen, ipmi_context_t context)
302a835eaa0SJia, Chunhui {
303a835eaa0SJia, Chunhui     GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
304a835eaa0SJia, Chunhui     GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
305a835eaa0SJia, Chunhui 
306a835eaa0SJia, Chunhui     if (*dataLen == 0)
307a835eaa0SJia, Chunhui     {
30864796041SJason M. Bills         *dataLen = 0;
309a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
310a835eaa0SJia, Chunhui     }
311a835eaa0SJia, Chunhui 
312a835eaa0SJia, Chunhui     size_t reqDataLen = *dataLen;
313a835eaa0SJia, Chunhui     *dataLen = 0;
31464796041SJason M. Bills     if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
315a835eaa0SJia, Chunhui     {
316a835eaa0SJia, Chunhui         return IPMI_CC_INVALID_FIELD_REQUEST;
317a835eaa0SJia, Chunhui     }
318a835eaa0SJia, Chunhui 
319a835eaa0SJia, Chunhui     // handle OEM command items
32064796041SJason M. Bills     switch (OEMDevEntityType(req->entityType))
321a835eaa0SJia, Chunhui     {
322a835eaa0SJia, Chunhui         case OEMDevEntityType::biosId:
323a835eaa0SJia, Chunhui         {
324a835eaa0SJia, Chunhui             if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
325a835eaa0SJia, Chunhui             {
326a835eaa0SJia, Chunhui                 return IPMI_CC_REQ_DATA_LEN_INVALID;
327a835eaa0SJia, Chunhui             }
328a835eaa0SJia, Chunhui 
32915419dd5SVernon Mauery             std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
33015419dd5SVernon Mauery             std::string service = getService(*dbus, biosIntf, biosObjPath);
331a835eaa0SJia, Chunhui             try
332a835eaa0SJia, Chunhui             {
33315419dd5SVernon Mauery                 Value variant = getDbusProperty(*dbus, service, biosObjPath,
334a835eaa0SJia, Chunhui                                                 biosIntf, biosProp);
3358166c8d7SVernon Mauery                 std::string& idString = std::get<std::string>(variant);
336a835eaa0SJia, Chunhui                 if (req->offset >= idString.size())
337a835eaa0SJia, Chunhui                 {
338a835eaa0SJia, Chunhui                     return IPMI_CC_PARM_OUT_OF_RANGE;
339a835eaa0SJia, Chunhui                 }
340a835eaa0SJia, Chunhui                 size_t length = 0;
341a835eaa0SJia, Chunhui                 if (req->countToRead > (idString.size() - req->offset))
342a835eaa0SJia, Chunhui                 {
343a835eaa0SJia, Chunhui                     length = idString.size() - req->offset;
344a835eaa0SJia, Chunhui                 }
345a835eaa0SJia, Chunhui                 else
346a835eaa0SJia, Chunhui                 {
347a835eaa0SJia, Chunhui                     length = req->countToRead;
348a835eaa0SJia, Chunhui                 }
349a835eaa0SJia, Chunhui                 std::copy(idString.begin() + req->offset, idString.end(),
350a835eaa0SJia, Chunhui                           res->data);
351a835eaa0SJia, Chunhui                 res->resDatalen = length;
352a835eaa0SJia, Chunhui                 *dataLen = res->resDatalen + 1;
353a835eaa0SJia, Chunhui             }
3548166c8d7SVernon Mauery             catch (std::bad_variant_access& e)
355a835eaa0SJia, Chunhui             {
35664796041SJason M. Bills                 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
357a835eaa0SJia, Chunhui                 return IPMI_CC_UNSPECIFIED_ERROR;
358a835eaa0SJia, Chunhui             }
359a835eaa0SJia, Chunhui         }
360a835eaa0SJia, Chunhui         break;
361a835eaa0SJia, Chunhui 
362a835eaa0SJia, Chunhui         case OEMDevEntityType::devVer:
363a835eaa0SJia, Chunhui         case OEMDevEntityType::sdrVer:
364a835eaa0SJia, Chunhui             // TODO:
365a835eaa0SJia, Chunhui             return IPMI_CC_ILLEGAL_COMMAND;
366a835eaa0SJia, Chunhui         default:
367a835eaa0SJia, Chunhui             return IPMI_CC_INVALID_FIELD_REQUEST;
368a835eaa0SJia, Chunhui     }
369a835eaa0SJia, Chunhui     return IPMI_CC_OK;
370a835eaa0SJia, Chunhui }
371a835eaa0SJia, Chunhui 
372a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
373a835eaa0SJia, Chunhui                             ipmi_request_t request, ipmi_response_t response,
374a835eaa0SJia, Chunhui                             ipmi_data_len_t dataLen, ipmi_context_t context)
375a835eaa0SJia, Chunhui {
376a835eaa0SJia, Chunhui     if (*dataLen != 0)
377a835eaa0SJia, Chunhui     {
37864796041SJason M. Bills         *dataLen = 0;
379a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
380a835eaa0SJia, Chunhui     }
381a835eaa0SJia, Chunhui 
382a835eaa0SJia, Chunhui     *dataLen = 1;
383a835eaa0SJia, Chunhui     uint8_t* res = reinterpret_cast<uint8_t*>(response);
384a835eaa0SJia, Chunhui     // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
385a835eaa0SJia, Chunhui     // AIC is available so that BIOS will not timeout repeatly which leads to
386a835eaa0SJia, Chunhui     // slow booting.
387a835eaa0SJia, Chunhui     *res = 0; // Byte1=Count of SlotPosition/FruID records.
388a835eaa0SJia, Chunhui     return IPMI_CC_OK;
389a835eaa0SJia, Chunhui }
390a835eaa0SJia, Chunhui 
39164796041SJason M. Bills ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
39264796041SJason M. Bills                                        ipmi_request_t request,
39364796041SJason M. Bills                                        ipmi_response_t response,
39464796041SJason M. Bills                                        ipmi_data_len_t dataLen,
39564796041SJason M. Bills                                        ipmi_context_t context)
396a835eaa0SJia, Chunhui {
39764796041SJason M. Bills     GetPowerRestoreDelayRes* resp =
39864796041SJason M. Bills         reinterpret_cast<GetPowerRestoreDelayRes*>(response);
39964796041SJason M. Bills 
40064796041SJason M. Bills     if (*dataLen != 0)
40164796041SJason M. Bills     {
40264796041SJason M. Bills         *dataLen = 0;
40364796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
404a835eaa0SJia, Chunhui     }
405a835eaa0SJia, Chunhui 
40615419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
40764796041SJason M. Bills     std::string service =
40815419dd5SVernon Mauery         getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
40964796041SJason M. Bills     Value variant =
41015419dd5SVernon Mauery         getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
41164796041SJason M. Bills                         powerRestoreDelayIntf, powerRestoreDelayProp);
41264796041SJason M. Bills 
4138166c8d7SVernon Mauery     uint16_t delay = std::get<uint16_t>(variant);
41464796041SJason M. Bills     resp->byteLSB = delay;
41564796041SJason M. Bills     resp->byteMSB = delay >> 8;
41664796041SJason M. Bills 
41764796041SJason M. Bills     *dataLen = sizeof(GetPowerRestoreDelayRes);
41864796041SJason M. Bills 
41964796041SJason M. Bills     return IPMI_CC_OK;
42064796041SJason M. Bills }
42164796041SJason M. Bills 
422cc49b54bSJia, Chunhui static uint8_t bcdToDec(uint8_t val)
423cc49b54bSJia, Chunhui {
424cc49b54bSJia, Chunhui     return ((val / 16 * 10) + (val % 16));
425cc49b54bSJia, Chunhui }
426cc49b54bSJia, Chunhui 
427cc49b54bSJia, Chunhui // Allows an update utility or system BIOS to send the status of an embedded
428cc49b54bSJia, Chunhui // firmware update attempt to the BMC. After received, BMC will create a logging
429cc49b54bSJia, Chunhui // record.
430cc49b54bSJia, Chunhui ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
431cc49b54bSJia, Chunhui                                                uint8_t majorRevision,
432cc49b54bSJia, Chunhui                                                uint8_t minorRevision,
433cc49b54bSJia, Chunhui                                                uint32_t auxInfo)
434cc49b54bSJia, Chunhui {
435cc49b54bSJia, Chunhui     std::string firmware;
436dc24927fSJason M. Bills     int instance = (target & targetInstanceMask) >> targetInstanceShift;
437cc49b54bSJia, Chunhui     target = (target & selEvtTargetMask) >> selEvtTargetShift;
438cc49b54bSJia, Chunhui 
439cc49b54bSJia, Chunhui     /* make sure the status is 0, 1, or 2 as per the spec */
440cc49b54bSJia, Chunhui     if (status > 2)
441cc49b54bSJia, Chunhui     {
442cc49b54bSJia, Chunhui         return ipmi::response(ipmi::ccInvalidFieldRequest);
443cc49b54bSJia, Chunhui     }
444dc24927fSJason M. Bills     /* make sure the target is 0, 1, 2, or 4 as per the spec */
445dc24927fSJason M. Bills     if (target > 4 || target == 3)
446dc24927fSJason M. Bills     {
447dc24927fSJason M. Bills         return ipmi::response(ipmi::ccInvalidFieldRequest);
448dc24927fSJason M. Bills     }
449cc49b54bSJia, Chunhui     /*orignal OEM command is to record OEM SEL.
450cc49b54bSJia, Chunhui     But openbmc does not support OEM SEL, so we redirect it to redfish event
451cc49b54bSJia, Chunhui     logging. */
452cc49b54bSJia, Chunhui     std::string buildInfo;
453cc49b54bSJia, Chunhui     std::string action;
454cc49b54bSJia, Chunhui     switch (FWUpdateTarget(target))
455cc49b54bSJia, Chunhui     {
456cc49b54bSJia, Chunhui         case FWUpdateTarget::targetBMC:
457cc49b54bSJia, Chunhui             firmware = "BMC";
458dc24927fSJason M. Bills             buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
459cc49b54bSJia, Chunhui                         std::to_string(bcdToDec(minorRevision)) + // BCD encoded
460cc49b54bSJia, Chunhui                         " BuildID: " + std::to_string(auxInfo);
461cc49b54bSJia, Chunhui             buildInfo += std::to_string(auxInfo);
462cc49b54bSJia, Chunhui             break;
463cc49b54bSJia, Chunhui         case FWUpdateTarget::targetBIOS:
464cc49b54bSJia, Chunhui             firmware = "BIOS";
465cc49b54bSJia, Chunhui             buildInfo =
466cc49b54bSJia, Chunhui                 "major: " +
467cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
468cc49b54bSJia, Chunhui                 " minor: " +
469cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
470cc49b54bSJia, Chunhui                 " ReleaseNumber: " +                      // ASCII encoded
471cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
472cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
473cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
474cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
475cc49b54bSJia, Chunhui             break;
476cc49b54bSJia, Chunhui         case FWUpdateTarget::targetME:
477cc49b54bSJia, Chunhui             firmware = "ME";
478cc49b54bSJia, Chunhui             buildInfo =
479cc49b54bSJia, Chunhui                 "major: " + std::to_string(majorRevision) + " minor1: " +
480cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
481cc49b54bSJia, Chunhui                 " minor2: " +
482cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
483cc49b54bSJia, Chunhui                 " build1: " +
484cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
485cc49b54bSJia, Chunhui                 " build2: " +
486cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
487cc49b54bSJia, Chunhui             break;
488cc49b54bSJia, Chunhui         case FWUpdateTarget::targetOEMEWS:
489cc49b54bSJia, Chunhui             firmware = "EWS";
490dc24927fSJason M. Bills             buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
491cc49b54bSJia, Chunhui                         std::to_string(bcdToDec(minorRevision)) + // BCD encoded
492cc49b54bSJia, Chunhui                         " BuildID: " + std::to_string(auxInfo);
493cc49b54bSJia, Chunhui             break;
494cc49b54bSJia, Chunhui     }
495cc49b54bSJia, Chunhui 
496dc24927fSJason M. Bills     static const std::string openBMCMessageRegistryVersion("0.1");
497dc24927fSJason M. Bills     std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
498dc24927fSJason M. Bills 
499cc49b54bSJia, Chunhui     switch (status)
500cc49b54bSJia, Chunhui     {
501cc49b54bSJia, Chunhui         case 0x0:
502cc49b54bSJia, Chunhui             action = "update started";
503dc24927fSJason M. Bills             redfishMsgID += ".FirmwareUpdateStarted";
504cc49b54bSJia, Chunhui             break;
505cc49b54bSJia, Chunhui         case 0x1:
506cc49b54bSJia, Chunhui             action = "update completed successfully";
507dc24927fSJason M. Bills             redfishMsgID += ".FirmwareUpdateCompleted";
508cc49b54bSJia, Chunhui             break;
509cc49b54bSJia, Chunhui         case 0x2:
510cc49b54bSJia, Chunhui             action = "update failure";
511dc24927fSJason M. Bills             redfishMsgID += ".FirmwareUpdateFailed";
512cc49b54bSJia, Chunhui             break;
513cc49b54bSJia, Chunhui         default:
514cc49b54bSJia, Chunhui             action = "unknown";
515cc49b54bSJia, Chunhui             break;
516cc49b54bSJia, Chunhui     }
517cc49b54bSJia, Chunhui 
518dc24927fSJason M. Bills     std::string firmwareInstanceStr =
519dc24927fSJason M. Bills         firmware + " instance: " + std::to_string(instance);
520dc24927fSJason M. Bills     std::string message("[firmware update] " + firmwareInstanceStr +
521cc49b54bSJia, Chunhui                         " status: <" + action + "> " + buildInfo);
522cc49b54bSJia, Chunhui 
523cc49b54bSJia, Chunhui     sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
524dc24927fSJason M. Bills                     "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
525dc24927fSJason M. Bills                     "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
526dc24927fSJason M. Bills                     buildInfo.c_str(), NULL);
527cc49b54bSJia, Chunhui     return ipmi::responseSuccess();
528cc49b54bSJia, Chunhui }
529cc49b54bSJia, Chunhui 
53064796041SJason M. Bills ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
53164796041SJason M. Bills                                        ipmi_request_t request,
53264796041SJason M. Bills                                        ipmi_response_t response,
53364796041SJason M. Bills                                        ipmi_data_len_t dataLen,
53464796041SJason M. Bills                                        ipmi_context_t context)
53564796041SJason M. Bills {
53664796041SJason M. Bills     SetPowerRestoreDelayReq* data =
53764796041SJason M. Bills         reinterpret_cast<SetPowerRestoreDelayReq*>(request);
53864796041SJason M. Bills     uint16_t delay = 0;
53964796041SJason M. Bills 
54064796041SJason M. Bills     if (*dataLen != sizeof(SetPowerRestoreDelayReq))
54164796041SJason M. Bills     {
54264796041SJason M. Bills         *dataLen = 0;
54364796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
54464796041SJason M. Bills     }
54564796041SJason M. Bills     delay = data->byteMSB;
54664796041SJason M. Bills     delay = (delay << 8) | data->byteLSB;
54715419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
54864796041SJason M. Bills     std::string service =
54915419dd5SVernon Mauery         getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
55015419dd5SVernon Mauery     setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
55164796041SJason M. Bills                     powerRestoreDelayIntf, powerRestoreDelayProp, delay);
55264796041SJason M. Bills     *dataLen = 0;
55364796041SJason M. Bills 
55464796041SJason M. Bills     return IPMI_CC_OK;
55564796041SJason M. Bills }
55664796041SJason M. Bills 
55742bd9c8eSJason M. Bills static bool cpuPresent(const std::string& cpuName)
55864796041SJason M. Bills {
55942bd9c8eSJason M. Bills     static constexpr const char* cpuPresencePathPrefix =
56042bd9c8eSJason M. Bills         "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
56142bd9c8eSJason M. Bills     static constexpr const char* cpuPresenceIntf =
56242bd9c8eSJason M. Bills         "xyz.openbmc_project.Inventory.Item";
56342bd9c8eSJason M. Bills     std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
56442bd9c8eSJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
56542bd9c8eSJason M. Bills     try
56642bd9c8eSJason M. Bills     {
56742bd9c8eSJason M. Bills         auto service =
56842bd9c8eSJason M. Bills             ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
56964796041SJason M. Bills 
57042bd9c8eSJason M. Bills         ipmi::Value result = ipmi::getDbusProperty(
57142bd9c8eSJason M. Bills             *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
57242bd9c8eSJason M. Bills         return std::get<bool>(result);
57342bd9c8eSJason M. Bills     }
57442bd9c8eSJason M. Bills     catch (const std::exception& e)
57564796041SJason M. Bills     {
57642bd9c8eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::INFO>(
57742bd9c8eSJason M. Bills             "Cannot find processor presence",
57842bd9c8eSJason M. Bills             phosphor::logging::entry("NAME=%s", cpuName.c_str()));
57942bd9c8eSJason M. Bills         return false;
58042bd9c8eSJason M. Bills     }
58164796041SJason M. Bills }
58264796041SJason M. Bills 
58342bd9c8eSJason M. Bills ipmi::RspType<bool,    // CATERR Reset Enabled
58442bd9c8eSJason M. Bills               bool,    // ERR2 Reset Enabled
58542bd9c8eSJason M. Bills               uint6_t, // reserved
58642bd9c8eSJason M. Bills               uint8_t, // reserved, returns 0x3F
58742bd9c8eSJason M. Bills               uint6_t, // CPU1 CATERR Count
58842bd9c8eSJason M. Bills               uint2_t, // CPU1 Status
58942bd9c8eSJason M. Bills               uint6_t, // CPU2 CATERR Count
59042bd9c8eSJason M. Bills               uint2_t, // CPU2 Status
59142bd9c8eSJason M. Bills               uint6_t, // CPU3 CATERR Count
59242bd9c8eSJason M. Bills               uint2_t, // CPU3 Status
59342bd9c8eSJason M. Bills               uint6_t, // CPU4 CATERR Count
59442bd9c8eSJason M. Bills               uint2_t, // CPU4 Status
59542bd9c8eSJason M. Bills               uint8_t  // Crashdump Count
59642bd9c8eSJason M. Bills               >
59742bd9c8eSJason M. Bills     ipmiOEMGetProcessorErrConfig()
59842bd9c8eSJason M. Bills {
59942bd9c8eSJason M. Bills     bool resetOnCATERR = false;
60042bd9c8eSJason M. Bills     bool resetOnERR2 = false;
60142bd9c8eSJason M. Bills     uint6_t cpu1CATERRCount = 0;
60242bd9c8eSJason M. Bills     uint6_t cpu2CATERRCount = 0;
60342bd9c8eSJason M. Bills     uint6_t cpu3CATERRCount = 0;
60442bd9c8eSJason M. Bills     uint6_t cpu4CATERRCount = 0;
60542bd9c8eSJason M. Bills     uint8_t crashdumpCount = 0;
60642bd9c8eSJason M. Bills     uint2_t cpu1Status =
60742bd9c8eSJason M. Bills         cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
60842bd9c8eSJason M. Bills     uint2_t cpu2Status =
60942bd9c8eSJason M. Bills         cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
61042bd9c8eSJason M. Bills     uint2_t cpu3Status =
61142bd9c8eSJason M. Bills         cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
61242bd9c8eSJason M. Bills     uint2_t cpu4Status =
61342bd9c8eSJason M. Bills         cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
61464796041SJason M. Bills 
61542bd9c8eSJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
61642bd9c8eSJason M. Bills     try
61742bd9c8eSJason M. Bills     {
61842bd9c8eSJason M. Bills         auto service = ipmi::getService(*busp, processorErrConfigIntf,
61942bd9c8eSJason M. Bills                                         processorErrConfigObjPath);
62064796041SJason M. Bills 
62142bd9c8eSJason M. Bills         ipmi::PropertyMap result = ipmi::getAllDbusProperties(
62242bd9c8eSJason M. Bills             *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
62342bd9c8eSJason M. Bills         resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
62442bd9c8eSJason M. Bills         resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
62542bd9c8eSJason M. Bills         cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
62642bd9c8eSJason M. Bills         cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
62742bd9c8eSJason M. Bills         cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
62842bd9c8eSJason M. Bills         cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
62942bd9c8eSJason M. Bills         crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
63042bd9c8eSJason M. Bills     }
63142bd9c8eSJason M. Bills     catch (const std::exception& e)
63242bd9c8eSJason M. Bills     {
63342bd9c8eSJason M. Bills         phosphor::logging::log<phosphor::logging::level::ERR>(
63442bd9c8eSJason M. Bills             "Failed to fetch processor error config",
63542bd9c8eSJason M. Bills             phosphor::logging::entry("ERROR=%s", e.what()));
63642bd9c8eSJason M. Bills         return ipmi::responseUnspecifiedError();
63742bd9c8eSJason M. Bills     }
63864796041SJason M. Bills 
63942bd9c8eSJason M. Bills     return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
64042bd9c8eSJason M. Bills                                  cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
64142bd9c8eSJason M. Bills                                  cpu2Status, cpu3CATERRCount, cpu3Status,
64242bd9c8eSJason M. Bills                                  cpu4CATERRCount, cpu4Status, crashdumpCount);
64342bd9c8eSJason M. Bills }
64442bd9c8eSJason M. Bills 
64542bd9c8eSJason M. Bills ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
64642bd9c8eSJason M. Bills     bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
64742bd9c8eSJason M. Bills     std::optional<bool> clearCPUErrorCount,
64842bd9c8eSJason M. Bills     std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
64942bd9c8eSJason M. Bills {
65042bd9c8eSJason M. Bills     std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
65164796041SJason M. Bills 
65264796041SJason M. Bills     try
65364796041SJason M. Bills     {
65442bd9c8eSJason M. Bills         auto service = ipmi::getService(*busp, processorErrConfigIntf,
65542bd9c8eSJason M. Bills                                         processorErrConfigObjPath);
65642bd9c8eSJason M. Bills         ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
65742bd9c8eSJason M. Bills                               processorErrConfigIntf, "ResetOnCATERR",
65842bd9c8eSJason M. Bills                               resetOnCATERR);
65942bd9c8eSJason M. Bills         ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
66042bd9c8eSJason M. Bills                               processorErrConfigIntf, "ResetOnERR2",
66142bd9c8eSJason M. Bills                               resetOnERR2);
66242bd9c8eSJason M. Bills         if (clearCPUErrorCount.value_or(false))
66342bd9c8eSJason M. Bills         {
66442bd9c8eSJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
665d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU1",
666d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
66742bd9c8eSJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
668d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU2",
669d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
670d3e19936SJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
671d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU3",
672d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
673d3e19936SJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
674d3e19936SJason M. Bills                                   processorErrConfigIntf, "ErrorCountCPU4",
675d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
67664796041SJason M. Bills         }
67742bd9c8eSJason M. Bills         if (clearCrashdumpCount.value_or(false))
67842bd9c8eSJason M. Bills         {
67942bd9c8eSJason M. Bills             ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
680d3e19936SJason M. Bills                                   processorErrConfigIntf, "CrashdumpCount",
681d3e19936SJason M. Bills                                   static_cast<uint8_t>(0));
68242bd9c8eSJason M. Bills         }
68342bd9c8eSJason M. Bills     }
68442bd9c8eSJason M. Bills     catch (std::exception& e)
68564796041SJason M. Bills     {
686bc546679SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(
68742bd9c8eSJason M. Bills             "Failed to set processor error config",
68842bd9c8eSJason M. Bills             phosphor::logging::entry("EXCEPTION=%s", e.what()));
68942bd9c8eSJason M. Bills         return ipmi::responseUnspecifiedError();
69064796041SJason M. Bills     }
69164796041SJason M. Bills 
69242bd9c8eSJason M. Bills     return ipmi::responseSuccess();
69364796041SJason M. Bills }
69464796041SJason M. Bills 
695703922d0SYong Li ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
696703922d0SYong Li                                     ipmi_request_t request,
697703922d0SYong Li                                     ipmi_response_t response,
698703922d0SYong Li                                     ipmi_data_len_t dataLen,
699703922d0SYong Li                                     ipmi_context_t context)
700703922d0SYong Li {
701703922d0SYong Li     GetOEMShutdownPolicyRes* resp =
702703922d0SYong Li         reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
703703922d0SYong Li 
704703922d0SYong Li     if (*dataLen != 0)
705703922d0SYong Li     {
706703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
70745f04988SKuiying Wang             "oem_get_shutdown_policy: invalid input len!");
708703922d0SYong Li         *dataLen = 0;
709703922d0SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
710703922d0SYong Li     }
711703922d0SYong Li 
712703922d0SYong Li     *dataLen = 0;
713703922d0SYong Li 
714703922d0SYong Li     try
715703922d0SYong Li     {
71615419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
717703922d0SYong Li         std::string service =
71815419dd5SVernon Mauery             getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
71915419dd5SVernon Mauery         Value variant = getDbusProperty(
72015419dd5SVernon Mauery             *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
721703922d0SYong Li             oemShutdownPolicyObjPathProp);
7220669d193SYong Li 
7230669d193SYong Li         if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
7240669d193SYong Li                 convertPolicyFromString(std::get<std::string>(variant)) ==
7250669d193SYong Li             sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
7260669d193SYong Li                 NoShutdownOnOCOT)
7270669d193SYong Li         {
7280669d193SYong Li             resp->policy = 0;
7290669d193SYong Li         }
7300669d193SYong Li         else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
7310669d193SYong Li                      convertPolicyFromString(std::get<std::string>(variant)) ==
7320669d193SYong Li                  sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
7330669d193SYong Li                      Policy::ShutdownOnOCOT)
7340669d193SYong Li         {
7350669d193SYong Li             resp->policy = 1;
7360669d193SYong Li         }
7370669d193SYong Li         else
7380669d193SYong Li         {
7390669d193SYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
7400669d193SYong Li                 "oem_set_shutdown_policy: invalid property!",
7410669d193SYong Li                 phosphor::logging::entry(
7420669d193SYong Li                     "PROP=%s", std::get<std::string>(variant).c_str()));
7430669d193SYong Li             return IPMI_CC_UNSPECIFIED_ERROR;
7440669d193SYong Li         }
745703922d0SYong Li         // TODO needs to check if it is multi-node products,
746703922d0SYong Li         // policy is only supported on node 3/4
747703922d0SYong Li         resp->policySupport = shutdownPolicySupported;
748703922d0SYong Li     }
749703922d0SYong Li     catch (sdbusplus::exception_t& e)
750703922d0SYong Li     {
751703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
752703922d0SYong Li         return IPMI_CC_UNSPECIFIED_ERROR;
753703922d0SYong Li     }
754703922d0SYong Li 
755703922d0SYong Li     *dataLen = sizeof(GetOEMShutdownPolicyRes);
756703922d0SYong Li     return IPMI_CC_OK;
757703922d0SYong Li }
758703922d0SYong Li 
759703922d0SYong Li ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
760703922d0SYong Li                                     ipmi_request_t request,
761703922d0SYong Li                                     ipmi_response_t response,
762703922d0SYong Li                                     ipmi_data_len_t dataLen,
763703922d0SYong Li                                     ipmi_context_t context)
764703922d0SYong Li {
765703922d0SYong Li     uint8_t* req = reinterpret_cast<uint8_t*>(request);
7660669d193SYong Li     sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
7670669d193SYong Li         sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
7680669d193SYong Li             NoShutdownOnOCOT;
769703922d0SYong Li 
770703922d0SYong Li     // TODO needs to check if it is multi-node products,
771703922d0SYong Li     // policy is only supported on node 3/4
772703922d0SYong Li     if (*dataLen != 1)
773703922d0SYong Li     {
774703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
775703922d0SYong Li             "oem_set_shutdown_policy: invalid input len!");
776703922d0SYong Li         *dataLen = 0;
777703922d0SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
778703922d0SYong Li     }
779703922d0SYong Li 
780703922d0SYong Li     *dataLen = 0;
781703922d0SYong Li     if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
782703922d0SYong Li     {
783703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
784703922d0SYong Li             "oem_set_shutdown_policy: invalid input!");
785703922d0SYong Li         return IPMI_CC_INVALID_FIELD_REQUEST;
786703922d0SYong Li     }
787703922d0SYong Li 
7880669d193SYong Li     if (*req == noShutdownOnOCOT)
7890669d193SYong Li     {
7900669d193SYong Li         policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
7910669d193SYong Li             Policy::NoShutdownOnOCOT;
7920669d193SYong Li     }
7930669d193SYong Li     else
7940669d193SYong Li     {
7950669d193SYong Li         policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
7960669d193SYong Li             Policy::ShutdownOnOCOT;
7970669d193SYong Li     }
7980669d193SYong Li 
799703922d0SYong Li     try
800703922d0SYong Li     {
80115419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
802703922d0SYong Li         std::string service =
80315419dd5SVernon Mauery             getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
8040669d193SYong Li         setDbusProperty(
80515419dd5SVernon Mauery             *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
8060669d193SYong Li             oemShutdownPolicyObjPathProp,
8070669d193SYong Li             sdbusplus::com::intel::Control::server::convertForMessage(policy));
808703922d0SYong Li     }
809703922d0SYong Li     catch (sdbusplus::exception_t& e)
810703922d0SYong Li     {
811703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
812703922d0SYong Li         return IPMI_CC_UNSPECIFIED_ERROR;
813703922d0SYong Li     }
814703922d0SYong Li 
815703922d0SYong Li     return IPMI_CC_OK;
816703922d0SYong Li }
817703922d0SYong Li 
818d509eb91SSuryakanth Sekar /** @brief implementation for check the DHCP or not in IPv4
819d509eb91SSuryakanth Sekar  *  @param[in] Channel - Channel number
820d509eb91SSuryakanth Sekar  *  @returns true or false.
821d509eb91SSuryakanth Sekar  */
822d509eb91SSuryakanth Sekar static bool isDHCPEnabled(uint8_t Channel)
823d509eb91SSuryakanth Sekar {
824d509eb91SSuryakanth Sekar     try
825d509eb91SSuryakanth Sekar     {
826d509eb91SSuryakanth Sekar         auto ethdevice = getChannelName(Channel);
827d509eb91SSuryakanth Sekar         if (ethdevice.empty())
828d509eb91SSuryakanth Sekar         {
829d509eb91SSuryakanth Sekar             return false;
830d509eb91SSuryakanth Sekar         }
831d509eb91SSuryakanth Sekar         auto ethIP = ethdevice + "/ipv4";
83215419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
833d509eb91SSuryakanth Sekar         auto ethernetObj =
83415419dd5SVernon Mauery             getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
83515419dd5SVernon Mauery         auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
836d509eb91SSuryakanth Sekar                                      networkIPIntf, "Origin");
8378166c8d7SVernon Mauery         if (std::get<std::string>(value) ==
838d509eb91SSuryakanth Sekar             "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
839d509eb91SSuryakanth Sekar         {
840d509eb91SSuryakanth Sekar             return true;
841d509eb91SSuryakanth Sekar         }
842d509eb91SSuryakanth Sekar         else
843d509eb91SSuryakanth Sekar         {
844d509eb91SSuryakanth Sekar             return false;
845d509eb91SSuryakanth Sekar         }
846d509eb91SSuryakanth Sekar     }
847d509eb91SSuryakanth Sekar     catch (sdbusplus::exception_t& e)
848d509eb91SSuryakanth Sekar     {
849d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
850d509eb91SSuryakanth Sekar         return true;
851d509eb91SSuryakanth Sekar     }
852d509eb91SSuryakanth Sekar }
853d509eb91SSuryakanth Sekar 
854d509eb91SSuryakanth Sekar /** @brief implementes for check the DHCP or not in IPv6
855d509eb91SSuryakanth Sekar  *  @param[in] Channel - Channel number
856d509eb91SSuryakanth Sekar  *  @returns true or false.
857d509eb91SSuryakanth Sekar  */
858d509eb91SSuryakanth Sekar static bool isDHCPIPv6Enabled(uint8_t Channel)
859d509eb91SSuryakanth Sekar {
860d509eb91SSuryakanth Sekar 
861d509eb91SSuryakanth Sekar     try
862d509eb91SSuryakanth Sekar     {
863d509eb91SSuryakanth Sekar         auto ethdevice = getChannelName(Channel);
864d509eb91SSuryakanth Sekar         if (ethdevice.empty())
865d509eb91SSuryakanth Sekar         {
866d509eb91SSuryakanth Sekar             return false;
867d509eb91SSuryakanth Sekar         }
868d509eb91SSuryakanth Sekar         auto ethIP = ethdevice + "/ipv6";
86915419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
870d509eb91SSuryakanth Sekar         auto objectInfo =
87115419dd5SVernon Mauery             getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
87215419dd5SVernon Mauery         auto properties = getAllDbusProperties(*dbus, objectInfo.second,
873d509eb91SSuryakanth Sekar                                                objectInfo.first, networkIPIntf);
8748166c8d7SVernon Mauery         if (std::get<std::string>(properties["Origin"]) ==
875d509eb91SSuryakanth Sekar             "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
876d509eb91SSuryakanth Sekar         {
877d509eb91SSuryakanth Sekar             return true;
878d509eb91SSuryakanth Sekar         }
879d509eb91SSuryakanth Sekar         else
880d509eb91SSuryakanth Sekar         {
881d509eb91SSuryakanth Sekar             return false;
882d509eb91SSuryakanth Sekar         }
883d509eb91SSuryakanth Sekar     }
884d509eb91SSuryakanth Sekar     catch (sdbusplus::exception_t& e)
885d509eb91SSuryakanth Sekar     {
886d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
887d509eb91SSuryakanth Sekar         return true;
888d509eb91SSuryakanth Sekar     }
889d509eb91SSuryakanth Sekar }
890d509eb91SSuryakanth Sekar 
891d509eb91SSuryakanth Sekar /** @brief implementes the creating of default new user
892d509eb91SSuryakanth Sekar  *  @param[in] userName - new username in 16 bytes.
893d509eb91SSuryakanth Sekar  *  @param[in] userPassword - new password in 20 bytes
894d509eb91SSuryakanth Sekar  *  @returns ipmi completion code.
895d509eb91SSuryakanth Sekar  */
896d509eb91SSuryakanth Sekar ipmi::RspType<> ipmiOEMSetUser2Activation(
897d509eb91SSuryakanth Sekar     std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
898d509eb91SSuryakanth Sekar     std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
899d509eb91SSuryakanth Sekar {
900d509eb91SSuryakanth Sekar     bool userState = false;
901d509eb91SSuryakanth Sekar     // Check for System Interface not exist and LAN should be static
902d509eb91SSuryakanth Sekar     for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
903d509eb91SSuryakanth Sekar     {
904d509eb91SSuryakanth Sekar         ChannelInfo chInfo;
905d509eb91SSuryakanth Sekar         try
906d509eb91SSuryakanth Sekar         {
907d509eb91SSuryakanth Sekar             getChannelInfo(channel, chInfo);
908d509eb91SSuryakanth Sekar         }
909d509eb91SSuryakanth Sekar         catch (sdbusplus::exception_t& e)
910d509eb91SSuryakanth Sekar         {
911d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
912d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
913d509eb91SSuryakanth Sekar                 phosphor::logging::entry("MSG: %s", e.description()));
914d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccUnspecifiedError);
915d509eb91SSuryakanth Sekar         }
916d509eb91SSuryakanth Sekar         if (chInfo.mediumType ==
917d509eb91SSuryakanth Sekar             static_cast<uint8_t>(EChannelMediumType::systemInterface))
918d509eb91SSuryakanth Sekar         {
919d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
920d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: system interface  exist .");
921d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
922d509eb91SSuryakanth Sekar         }
923d509eb91SSuryakanth Sekar         else
924d509eb91SSuryakanth Sekar         {
925d509eb91SSuryakanth Sekar 
926d509eb91SSuryakanth Sekar             if (chInfo.mediumType ==
927d509eb91SSuryakanth Sekar                 static_cast<uint8_t>(EChannelMediumType::lan8032))
928d509eb91SSuryakanth Sekar             {
929d509eb91SSuryakanth Sekar                 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
930d509eb91SSuryakanth Sekar                 {
931d509eb91SSuryakanth Sekar                     phosphor::logging::log<phosphor::logging::level::ERR>(
932d509eb91SSuryakanth Sekar                         "ipmiOEMSetUser2Activation: DHCP enabled .");
933d509eb91SSuryakanth Sekar                     return ipmi::response(ipmi::ccCommandNotAvailable);
934d509eb91SSuryakanth Sekar                 }
935d509eb91SSuryakanth Sekar             }
936d509eb91SSuryakanth Sekar         }
937d509eb91SSuryakanth Sekar     }
938d509eb91SSuryakanth Sekar     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
939d509eb91SSuryakanth Sekar     if (ipmi::ccSuccess ==
940d509eb91SSuryakanth Sekar         ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
941d509eb91SSuryakanth Sekar     {
942d509eb91SSuryakanth Sekar         if (enabledUsers > 1)
943d509eb91SSuryakanth Sekar         {
944d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
945d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: more than one user is enabled.");
946d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
947d509eb91SSuryakanth Sekar         }
948d509eb91SSuryakanth Sekar         // Check the user 2 is enabled or not
949d509eb91SSuryakanth Sekar         ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
950d509eb91SSuryakanth Sekar         if (userState == true)
951d509eb91SSuryakanth Sekar         {
952d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
953d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: user 2 already enabled .");
954d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
955d509eb91SSuryakanth Sekar         }
956d509eb91SSuryakanth Sekar     }
957d509eb91SSuryakanth Sekar     else
958d509eb91SSuryakanth Sekar     {
959d509eb91SSuryakanth Sekar         return ipmi::response(ipmi::ccUnspecifiedError);
960d509eb91SSuryakanth Sekar     }
961d509eb91SSuryakanth Sekar 
962d509eb91SSuryakanth Sekar #if BYTE_ORDER == LITTLE_ENDIAN
963d509eb91SSuryakanth Sekar     PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
964d509eb91SSuryakanth Sekar #endif
965d509eb91SSuryakanth Sekar #if BYTE_ORDER == BIG_ENDIAN
966d509eb91SSuryakanth Sekar     PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
967d509eb91SSuryakanth Sekar #endif
968d509eb91SSuryakanth Sekar 
969d509eb91SSuryakanth Sekar     if (ipmi::ccSuccess ==
970d509eb91SSuryakanth Sekar         ipmiUserSetUserName(ipmiDefaultUserId,
971d509eb91SSuryakanth Sekar                             reinterpret_cast<const char*>(userName.data())))
972d509eb91SSuryakanth Sekar     {
973d509eb91SSuryakanth Sekar         if (ipmi::ccSuccess ==
974d509eb91SSuryakanth Sekar             ipmiUserSetUserPassword(
975d509eb91SSuryakanth Sekar                 ipmiDefaultUserId,
976d509eb91SSuryakanth Sekar                 reinterpret_cast<const char*>(userPassword.data())))
977d509eb91SSuryakanth Sekar         {
978d509eb91SSuryakanth Sekar             if (ipmi::ccSuccess ==
979d509eb91SSuryakanth Sekar                 ipmiUserSetPrivilegeAccess(
980d509eb91SSuryakanth Sekar                     ipmiDefaultUserId,
981d509eb91SSuryakanth Sekar                     static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
982d509eb91SSuryakanth Sekar                     privAccess, true))
983d509eb91SSuryakanth Sekar             {
984d509eb91SSuryakanth Sekar                 phosphor::logging::log<phosphor::logging::level::INFO>(
985d509eb91SSuryakanth Sekar                     "ipmiOEMSetUser2Activation: user created successfully ");
986d509eb91SSuryakanth Sekar                 return ipmi::responseSuccess();
987d509eb91SSuryakanth Sekar             }
988d509eb91SSuryakanth Sekar         }
989d509eb91SSuryakanth Sekar         // we need to delete  the default user id which added in this command as
990d509eb91SSuryakanth Sekar         // password / priv setting is failed.
991d509eb91SSuryakanth Sekar         ipmiUserSetUserName(ipmiDefaultUserId, "");
992d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(
993d509eb91SSuryakanth Sekar             "ipmiOEMSetUser2Activation: password / priv setting is failed.");
994d509eb91SSuryakanth Sekar     }
995d509eb91SSuryakanth Sekar     else
996d509eb91SSuryakanth Sekar     {
997d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(
998d509eb91SSuryakanth Sekar             "ipmiOEMSetUser2Activation: Setting username failed.");
999d509eb91SSuryakanth Sekar     }
1000d509eb91SSuryakanth Sekar 
1001d509eb91SSuryakanth Sekar     return ipmi::response(ipmi::ccCommandNotAvailable);
1002d509eb91SSuryakanth Sekar }
1003d509eb91SSuryakanth Sekar 
1004fc5e985bSRichard Marian Thomaiyar /** @brief implementes setting password for special user
1005fc5e985bSRichard Marian Thomaiyar  *  @param[in] specialUserIndex
1006fc5e985bSRichard Marian Thomaiyar  *  @param[in] userPassword - new password in 20 bytes
1007fc5e985bSRichard Marian Thomaiyar  *  @returns ipmi completion code.
1008fc5e985bSRichard Marian Thomaiyar  */
1009fc5e985bSRichard Marian Thomaiyar ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1010fc5e985bSRichard Marian Thomaiyar                                               uint8_t specialUserIndex,
1011fc5e985bSRichard Marian Thomaiyar                                               std::vector<uint8_t> userPassword)
1012fc5e985bSRichard Marian Thomaiyar {
1013fc5e985bSRichard Marian Thomaiyar     ChannelInfo chInfo;
1014fc5e985bSRichard Marian Thomaiyar     try
1015fc5e985bSRichard Marian Thomaiyar     {
1016fc5e985bSRichard Marian Thomaiyar         getChannelInfo(ctx->channel, chInfo);
1017fc5e985bSRichard Marian Thomaiyar     }
1018fc5e985bSRichard Marian Thomaiyar     catch (sdbusplus::exception_t& e)
1019fc5e985bSRichard Marian Thomaiyar     {
1020fc5e985bSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
1021fc5e985bSRichard Marian Thomaiyar             "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1022fc5e985bSRichard Marian Thomaiyar             phosphor::logging::entry("MSG: %s", e.description()));
1023fc5e985bSRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
1024fc5e985bSRichard Marian Thomaiyar     }
1025fc5e985bSRichard Marian Thomaiyar     if (chInfo.mediumType !=
1026fc5e985bSRichard Marian Thomaiyar         static_cast<uint8_t>(EChannelMediumType::systemInterface))
1027fc5e985bSRichard Marian Thomaiyar     {
1028fc5e985bSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
1029fc5e985bSRichard Marian Thomaiyar             "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1030fc5e985bSRichard Marian Thomaiyar             "interface");
1031fc5e985bSRichard Marian Thomaiyar         return ipmi::responseCommandNotAvailable();
1032fc5e985bSRichard Marian Thomaiyar     }
1033fc5e985bSRichard Marian Thomaiyar     if (specialUserIndex != 0)
1034fc5e985bSRichard Marian Thomaiyar     {
1035fc5e985bSRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
1036fc5e985bSRichard Marian Thomaiyar             "ipmiOEMSetSpecialUserPassword: Invalid user account");
1037fc5e985bSRichard Marian Thomaiyar         return ipmi::responseParmOutOfRange();
1038fc5e985bSRichard Marian Thomaiyar     }
1039fc5e985bSRichard Marian Thomaiyar     constexpr uint8_t minPasswordSizeRequired = 6;
1040fc5e985bSRichard Marian Thomaiyar     if (userPassword.size() < minPasswordSizeRequired ||
1041fc5e985bSRichard Marian Thomaiyar         userPassword.size() > ipmi::maxIpmi20PasswordSize)
1042fc5e985bSRichard Marian Thomaiyar     {
1043fc5e985bSRichard Marian Thomaiyar         return ipmi::responseReqDataLenInvalid();
1044fc5e985bSRichard Marian Thomaiyar     }
1045fc5e985bSRichard Marian Thomaiyar     std::string passwd;
1046fc5e985bSRichard Marian Thomaiyar     passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1047fc5e985bSRichard Marian Thomaiyar                   userPassword.size());
1048fc5e985bSRichard Marian Thomaiyar     return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
1049fc5e985bSRichard Marian Thomaiyar }
1050fc5e985bSRichard Marian Thomaiyar 
105145f04988SKuiying Wang namespace ledAction
105245f04988SKuiying Wang {
105345f04988SKuiying Wang using namespace sdbusplus::xyz::openbmc_project::Led::server;
105445f04988SKuiying Wang std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
105545f04988SKuiying Wang     {Physical::Action::Off, 0x00},
105645f04988SKuiying Wang     {Physical::Action::On, 0x10},
105745f04988SKuiying Wang     {Physical::Action::Blink, 0x01}};
105845f04988SKuiying Wang 
105945f04988SKuiying Wang std::map<uint8_t, std::string> offsetObjPath = {
106045f04988SKuiying Wang     {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
106145f04988SKuiying Wang 
106245f04988SKuiying Wang } // namespace ledAction
106345f04988SKuiying Wang 
106445f04988SKuiying Wang int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
106545f04988SKuiying Wang                    const std::string& objPath, uint8_t& state)
106645f04988SKuiying Wang {
106745f04988SKuiying Wang     try
106845f04988SKuiying Wang     {
106945f04988SKuiying Wang         std::string service = getService(bus, intf, objPath);
107045f04988SKuiying Wang         Value stateValue =
107145f04988SKuiying Wang             getDbusProperty(bus, service, objPath, intf, "State");
10728166c8d7SVernon Mauery         std::string strState = std::get<std::string>(stateValue);
107345f04988SKuiying Wang         state = ledAction::actionDbusToIpmi.at(
107445f04988SKuiying Wang             sdbusplus::xyz::openbmc_project::Led::server::Physical::
107545f04988SKuiying Wang                 convertActionFromString(strState));
107645f04988SKuiying Wang     }
107745f04988SKuiying Wang     catch (sdbusplus::exception::SdBusError& e)
107845f04988SKuiying Wang     {
107945f04988SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
108045f04988SKuiying Wang         return -1;
108145f04988SKuiying Wang     }
108245f04988SKuiying Wang     return 0;
108345f04988SKuiying Wang }
108445f04988SKuiying Wang 
108545f04988SKuiying Wang ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
108645f04988SKuiying Wang                                ipmi_request_t request, ipmi_response_t response,
108745f04988SKuiying Wang                                ipmi_data_len_t dataLen, ipmi_context_t context)
108845f04988SKuiying Wang {
108945f04988SKuiying Wang     uint8_t* resp = reinterpret_cast<uint8_t*>(response);
109045f04988SKuiying Wang     // LED Status
109145f04988SKuiying Wang     //[1:0] = Reserved
109245f04988SKuiying Wang     //[3:2] = Status(Amber)
109345f04988SKuiying Wang     //[5:4] = Status(Green)
109445f04988SKuiying Wang     //[7:6] = System Identify
109545f04988SKuiying Wang     // Status definitions:
109645f04988SKuiying Wang     // 00b = Off
109745f04988SKuiying Wang     // 01b = Blink
109845f04988SKuiying Wang     // 10b = On
109945f04988SKuiying Wang     // 11b = invalid
110045f04988SKuiying Wang     if (*dataLen != 0)
110145f04988SKuiying Wang     {
110245f04988SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(
110345f04988SKuiying Wang             "oem_get_led_status: invalid input len!");
110445f04988SKuiying Wang         *dataLen = 0;
110545f04988SKuiying Wang         return IPMI_CC_REQ_DATA_LEN_INVALID;
110645f04988SKuiying Wang     }
110745f04988SKuiying Wang 
110845f04988SKuiying Wang     phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
110945f04988SKuiying Wang     *resp = 0;
111045f04988SKuiying Wang     *dataLen = 0;
111115419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
111245f04988SKuiying Wang     for (auto it = ledAction::offsetObjPath.begin();
111345f04988SKuiying Wang          it != ledAction::offsetObjPath.end(); ++it)
111445f04988SKuiying Wang     {
111545f04988SKuiying Wang         uint8_t state = 0;
111615419dd5SVernon Mauery         if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
111745f04988SKuiying Wang         {
111845f04988SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
111945f04988SKuiying Wang                 "oem_get_led_status: fail to get ID LED status!");
112045f04988SKuiying Wang             return IPMI_CC_UNSPECIFIED_ERROR;
112145f04988SKuiying Wang         }
112245f04988SKuiying Wang         *resp |= state << it->first;
112345f04988SKuiying Wang     }
112445f04988SKuiying Wang 
112545f04988SKuiying Wang     *dataLen = sizeof(*resp);
112645f04988SKuiying Wang     return IPMI_CC_OK;
112745f04988SKuiying Wang }
112845f04988SKuiying Wang 
112923737fe3SYong Li ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
113023737fe3SYong Li                                          ipmi_request_t request,
113123737fe3SYong Li                                          ipmi_response_t response,
113223737fe3SYong Li                                          ipmi_data_len_t dataLen,
113323737fe3SYong Li                                          ipmi_context_t context)
113423737fe3SYong Li {
113523737fe3SYong Li     CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
113623737fe3SYong Li     uint8_t* resp = reinterpret_cast<uint8_t*>(response);
113723737fe3SYong Li 
113823737fe3SYong Li     if (*dataLen == 0)
113923737fe3SYong Li     {
114023737fe3SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
114123737fe3SYong Li             "CfgHostSerial: invalid input len!",
114223737fe3SYong Li             phosphor::logging::entry("LEN=%d", *dataLen));
114323737fe3SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
114423737fe3SYong Li     }
114523737fe3SYong Li 
114623737fe3SYong Li     switch (req->command)
114723737fe3SYong Li     {
114823737fe3SYong Li         case getHostSerialCfgCmd:
114923737fe3SYong Li         {
115023737fe3SYong Li             if (*dataLen != 1)
115123737fe3SYong Li             {
115223737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
115323737fe3SYong Li                     "CfgHostSerial: invalid input len!");
115423737fe3SYong Li                 *dataLen = 0;
115523737fe3SYong Li                 return IPMI_CC_REQ_DATA_LEN_INVALID;
115623737fe3SYong Li             }
115723737fe3SYong Li 
115823737fe3SYong Li             *dataLen = 0;
115923737fe3SYong Li 
116023737fe3SYong Li             boost::process::ipstream is;
116123737fe3SYong Li             std::vector<std::string> data;
116223737fe3SYong Li             std::string line;
116323737fe3SYong Li             boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
116423737fe3SYong Li                                      boost::process::std_out > is);
116523737fe3SYong Li 
116623737fe3SYong Li             while (c1.running() && std::getline(is, line) && !line.empty())
116723737fe3SYong Li             {
116823737fe3SYong Li                 data.push_back(line);
116923737fe3SYong Li             }
117023737fe3SYong Li 
117123737fe3SYong Li             c1.wait();
117223737fe3SYong Li             if (c1.exit_code())
117323737fe3SYong Li             {
117423737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
117523737fe3SYong Li                     "CfgHostSerial:: error on execute",
117623737fe3SYong Li                     phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
117723737fe3SYong Li                 // Using the default value
117823737fe3SYong Li                 *resp = 0;
117923737fe3SYong Li             }
118023737fe3SYong Li             else
118123737fe3SYong Li             {
118223737fe3SYong Li                 if (data.size() != 1)
118323737fe3SYong Li                 {
118423737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
118523737fe3SYong Li                         "CfgHostSerial:: error on read env");
118623737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
118723737fe3SYong Li                 }
118823737fe3SYong Li                 try
118923737fe3SYong Li                 {
119023737fe3SYong Li                     unsigned long tmp = std::stoul(data[0]);
119123737fe3SYong Li                     if (tmp > std::numeric_limits<uint8_t>::max())
119223737fe3SYong Li                     {
119323737fe3SYong Li                         throw std::out_of_range("Out of range");
119423737fe3SYong Li                     }
119523737fe3SYong Li                     *resp = static_cast<uint8_t>(tmp);
119623737fe3SYong Li                 }
119723737fe3SYong Li                 catch (const std::invalid_argument& e)
119823737fe3SYong Li                 {
119923737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
120023737fe3SYong Li                         "invalid config ",
120123737fe3SYong Li                         phosphor::logging::entry("ERR=%s", e.what()));
120223737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
120323737fe3SYong Li                 }
120423737fe3SYong Li                 catch (const std::out_of_range& e)
120523737fe3SYong Li                 {
120623737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
120723737fe3SYong Li                         "out_of_range config ",
120823737fe3SYong Li                         phosphor::logging::entry("ERR=%s", e.what()));
120923737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
121023737fe3SYong Li                 }
121123737fe3SYong Li             }
121223737fe3SYong Li 
121323737fe3SYong Li             *dataLen = 1;
121423737fe3SYong Li             break;
121523737fe3SYong Li         }
121623737fe3SYong Li         case setHostSerialCfgCmd:
121723737fe3SYong Li         {
121823737fe3SYong Li             if (*dataLen != sizeof(CfgHostSerialReq))
121923737fe3SYong Li             {
122023737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
122123737fe3SYong Li                     "CfgHostSerial: invalid input len!");
122223737fe3SYong Li                 *dataLen = 0;
122323737fe3SYong Li                 return IPMI_CC_REQ_DATA_LEN_INVALID;
122423737fe3SYong Li             }
122523737fe3SYong Li 
122623737fe3SYong Li             *dataLen = 0;
122723737fe3SYong Li 
122823737fe3SYong Li             if (req->parameter > HostSerialCfgParamMax)
122923737fe3SYong Li             {
123023737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
123123737fe3SYong Li                     "CfgHostSerial: invalid input!");
123223737fe3SYong Li                 return IPMI_CC_INVALID_FIELD_REQUEST;
123323737fe3SYong Li             }
123423737fe3SYong Li 
123523737fe3SYong Li             boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
123623737fe3SYong Li                                      std::to_string(req->parameter));
123723737fe3SYong Li 
123823737fe3SYong Li             c1.wait();
123923737fe3SYong Li             if (c1.exit_code())
124023737fe3SYong Li             {
124123737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
124223737fe3SYong Li                     "CfgHostSerial:: error on execute",
124323737fe3SYong Li                     phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
124423737fe3SYong Li                 return IPMI_CC_UNSPECIFIED_ERROR;
124523737fe3SYong Li             }
124623737fe3SYong Li             break;
124723737fe3SYong Li         }
124823737fe3SYong Li         default:
124923737fe3SYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
125023737fe3SYong Li                 "CfgHostSerial: invalid input!");
125123737fe3SYong Li             *dataLen = 0;
125223737fe3SYong Li             return IPMI_CC_INVALID_FIELD_REQUEST;
125323737fe3SYong Li     }
125423737fe3SYong Li 
125523737fe3SYong Li     return IPMI_CC_OK;
125623737fe3SYong Li }
125723737fe3SYong Li 
125891244a6aSJames Feist constexpr const char* thermalModeInterface =
125991244a6aSJames Feist     "xyz.openbmc_project.Control.ThermalMode";
126091244a6aSJames Feist constexpr const char* thermalModePath =
126191244a6aSJames Feist     "/xyz/openbmc_project/control/thermal_mode";
126291244a6aSJames Feist 
126391244a6aSJames Feist bool getFanProfileInterface(
126491244a6aSJames Feist     sdbusplus::bus::bus& bus,
126591244a6aSJames Feist     boost::container::flat_map<
126691244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>& resp)
126791244a6aSJames Feist {
126891244a6aSJames Feist     auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
126991244a6aSJames Feist                                     "GetAll");
127091244a6aSJames Feist     call.append(thermalModeInterface);
127191244a6aSJames Feist     try
127291244a6aSJames Feist     {
127391244a6aSJames Feist         auto data = bus.call(call);
127491244a6aSJames Feist         data.read(resp);
127591244a6aSJames Feist     }
127691244a6aSJames Feist     catch (sdbusplus::exception_t& e)
127791244a6aSJames Feist     {
127891244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
127991244a6aSJames Feist             "getFanProfileInterface: can't get thermal mode!",
128091244a6aSJames Feist             phosphor::logging::entry("ERR=%s", e.what()));
128191244a6aSJames Feist         return false;
128291244a6aSJames Feist     }
128391244a6aSJames Feist     return true;
128491244a6aSJames Feist }
128591244a6aSJames Feist 
128691244a6aSJames Feist ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
128791244a6aSJames Feist                                ipmi_request_t request, ipmi_response_t response,
128891244a6aSJames Feist                                ipmi_data_len_t dataLen, ipmi_context_t context)
128991244a6aSJames Feist {
129091244a6aSJames Feist 
129191244a6aSJames Feist     if (*dataLen < 2 || *dataLen > 7)
129291244a6aSJames Feist     {
129391244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
129491244a6aSJames Feist             "ipmiOEMSetFanConfig: invalid input len!");
129591244a6aSJames Feist         *dataLen = 0;
129691244a6aSJames Feist         return IPMI_CC_REQ_DATA_LEN_INVALID;
129791244a6aSJames Feist     }
129891244a6aSJames Feist 
129991244a6aSJames Feist     // todo: tell bios to only send first 2 bytes
130091244a6aSJames Feist 
130191244a6aSJames Feist     SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
130291244a6aSJames Feist     boost::container::flat_map<
130391244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>
130491244a6aSJames Feist         profileData;
130515419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
130615419dd5SVernon Mauery     if (!getFanProfileInterface(*dbus, profileData))
130791244a6aSJames Feist     {
130891244a6aSJames Feist         return IPMI_CC_UNSPECIFIED_ERROR;
130991244a6aSJames Feist     }
131091244a6aSJames Feist 
131191244a6aSJames Feist     std::vector<std::string>* supported =
131291244a6aSJames Feist         std::get_if<std::vector<std::string>>(&profileData["Supported"]);
131391244a6aSJames Feist     if (supported == nullptr)
131491244a6aSJames Feist     {
131591244a6aSJames Feist         return IPMI_CC_INVALID_FIELD_REQUEST;
131691244a6aSJames Feist     }
131791244a6aSJames Feist     std::string mode;
131891244a6aSJames Feist     if (req->flags &
131991244a6aSJames Feist         (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
132091244a6aSJames Feist     {
132191244a6aSJames Feist         bool performanceMode =
132291244a6aSJames Feist             (req->flags & (1 << static_cast<uint8_t>(
132391244a6aSJames Feist                                setFanProfileFlags::performAcousSelect))) > 0;
132491244a6aSJames Feist 
132591244a6aSJames Feist         if (performanceMode)
132691244a6aSJames Feist         {
132791244a6aSJames Feist 
132891244a6aSJames Feist             if (std::find(supported->begin(), supported->end(),
132991244a6aSJames Feist                           "Performance") != supported->end())
133091244a6aSJames Feist             {
133191244a6aSJames Feist                 mode = "Performance";
133291244a6aSJames Feist             }
133391244a6aSJames Feist         }
133491244a6aSJames Feist         else
133591244a6aSJames Feist         {
133691244a6aSJames Feist 
133791244a6aSJames Feist             if (std::find(supported->begin(), supported->end(), "Acoustic") !=
133891244a6aSJames Feist                 supported->end())
133991244a6aSJames Feist             {
134091244a6aSJames Feist                 mode = "Acoustic";
134191244a6aSJames Feist             }
134291244a6aSJames Feist         }
134391244a6aSJames Feist         if (mode.empty())
134491244a6aSJames Feist         {
134591244a6aSJames Feist             return IPMI_CC_INVALID_FIELD_REQUEST;
134691244a6aSJames Feist         }
134715419dd5SVernon Mauery         setDbusProperty(*dbus, settingsBusName, thermalModePath,
134891244a6aSJames Feist                         thermalModeInterface, "Current", mode);
134991244a6aSJames Feist     }
135091244a6aSJames Feist 
135191244a6aSJames Feist     return IPMI_CC_OK;
135291244a6aSJames Feist }
135391244a6aSJames Feist 
13545b693637SJames Feist ipmi::RspType<uint8_t, // profile support map
13555b693637SJames Feist               uint8_t, // fan control profile enable
13565b693637SJames Feist               uint8_t, // flags
13575b693637SJames Feist               uint32_t // dimm presence bit map
13585b693637SJames Feist               >
13595b693637SJames Feist     ipmiOEMGetFanConfig(uint8_t dimmGroupId)
136091244a6aSJames Feist {
136191244a6aSJames Feist     boost::container::flat_map<
136291244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>
136391244a6aSJames Feist         profileData;
136491244a6aSJames Feist 
136515419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
136615419dd5SVernon Mauery     if (!getFanProfileInterface(*dbus, profileData))
136791244a6aSJames Feist     {
13685b693637SJames Feist         return ipmi::responseResponseError();
136991244a6aSJames Feist     }
137091244a6aSJames Feist 
137191244a6aSJames Feist     std::string* current = std::get_if<std::string>(&profileData["Current"]);
137291244a6aSJames Feist 
137391244a6aSJames Feist     if (current == nullptr)
137491244a6aSJames Feist     {
137591244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
137691244a6aSJames Feist             "ipmiOEMGetFanConfig: can't get current mode!");
13775b693637SJames Feist         return ipmi::responseResponseError();
137891244a6aSJames Feist     }
137991244a6aSJames Feist     bool performance = (*current == "Performance");
138091244a6aSJames Feist 
13815b693637SJames Feist     uint8_t flags = 0;
138291244a6aSJames Feist     if (performance)
138391244a6aSJames Feist     {
13845b693637SJames Feist         flags |= 1 << 2;
138591244a6aSJames Feist     }
138691244a6aSJames Feist 
13875b693637SJames Feist     return ipmi::responseSuccess(0, 0, flags, 0);
138891244a6aSJames Feist }
13895f957cafSJames Feist constexpr const char* cfmLimitSettingPath =
13905f957cafSJames Feist     "/xyz/openbmc_project/control/cfm_limit";
13915f957cafSJames Feist constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
1392faa4f223SJames Feist constexpr const size_t legacyExitAirSensorNumber = 0x2e;
139309f6b604SJames Feist constexpr const size_t legacyPCHSensorNumber = 0x22;
139409f6b604SJames Feist constexpr const char* exitAirPathName = "Exit_Air";
139509f6b604SJames Feist constexpr const char* pchPathName = "SSB_Temp";
1396acc8a4ebSJames Feist constexpr const char* pidConfigurationIface =
1397acc8a4ebSJames Feist     "xyz.openbmc_project.Configuration.Pid";
1398faa4f223SJames Feist 
139909f6b604SJames Feist static std::string getConfigPath(const std::string& name)
1400faa4f223SJames Feist {
140115419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1402faa4f223SJames Feist     auto method =
140315419dd5SVernon Mauery         dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1404faa4f223SJames Feist                               "/xyz/openbmc_project/object_mapper",
1405faa4f223SJames Feist                               "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1406faa4f223SJames Feist 
1407acc8a4ebSJames Feist     method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1408faa4f223SJames Feist     std::string path;
1409faa4f223SJames Feist     GetSubTreeType resp;
1410faa4f223SJames Feist     try
1411faa4f223SJames Feist     {
141215419dd5SVernon Mauery         auto reply = dbus->call(method);
1413faa4f223SJames Feist         reply.read(resp);
1414faa4f223SJames Feist     }
1415faa4f223SJames Feist     catch (sdbusplus::exception_t&)
1416faa4f223SJames Feist     {
1417faa4f223SJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1418faa4f223SJames Feist             "ipmiOEMGetFscParameter: mapper error");
1419faa4f223SJames Feist     };
142009f6b604SJames Feist     auto config =
142109f6b604SJames Feist         std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
142209f6b604SJames Feist             return pair.first.find(name) != std::string::npos;
1423faa4f223SJames Feist         });
1424faa4f223SJames Feist     if (config != resp.end())
1425faa4f223SJames Feist     {
1426faa4f223SJames Feist         path = std::move(config->first);
1427faa4f223SJames Feist     }
1428faa4f223SJames Feist     return path;
1429faa4f223SJames Feist }
14305f957cafSJames Feist 
1431acc8a4ebSJames Feist // flat map to make alphabetical
1432acc8a4ebSJames Feist static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1433acc8a4ebSJames Feist {
1434acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> ret;
143515419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1436acc8a4ebSJames Feist     auto method =
143715419dd5SVernon Mauery         dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1438acc8a4ebSJames Feist                               "/xyz/openbmc_project/object_mapper",
1439acc8a4ebSJames Feist                               "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1440acc8a4ebSJames Feist 
1441acc8a4ebSJames Feist     method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1442acc8a4ebSJames Feist     GetSubTreeType resp;
1443acc8a4ebSJames Feist 
1444acc8a4ebSJames Feist     try
1445acc8a4ebSJames Feist     {
144615419dd5SVernon Mauery         auto reply = dbus->call(method);
1447acc8a4ebSJames Feist         reply.read(resp);
1448acc8a4ebSJames Feist     }
1449acc8a4ebSJames Feist     catch (sdbusplus::exception_t&)
1450acc8a4ebSJames Feist     {
1451acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1452acc8a4ebSJames Feist             "getFanConfigPaths: mapper error");
1453acc8a4ebSJames Feist     };
1454acc8a4ebSJames Feist     for (const auto& [path, objects] : resp)
1455acc8a4ebSJames Feist     {
1456acc8a4ebSJames Feist         if (objects.empty())
1457acc8a4ebSJames Feist         {
1458acc8a4ebSJames Feist             continue; // should be impossible
1459acc8a4ebSJames Feist         }
1460be560b09SZhu, Yunge 
1461be560b09SZhu, Yunge         try
1462be560b09SZhu, Yunge         {
146315419dd5SVernon Mauery             ret.emplace(path,
146415419dd5SVernon Mauery                         getAllDbusProperties(*dbus, objects[0].first, path,
1465acc8a4ebSJames Feist                                              pidConfigurationIface));
1466acc8a4ebSJames Feist         }
1467be560b09SZhu, Yunge         catch (sdbusplus::exception_t& e)
1468be560b09SZhu, Yunge         {
1469be560b09SZhu, Yunge             phosphor::logging::log<phosphor::logging::level::ERR>(
1470be560b09SZhu, Yunge                 "getPidConfigs: can't get DbusProperties!",
1471be560b09SZhu, Yunge                 phosphor::logging::entry("ERR=%s", e.what()));
1472be560b09SZhu, Yunge         }
1473be560b09SZhu, Yunge     }
1474acc8a4ebSJames Feist     return ret;
1475acc8a4ebSJames Feist }
1476acc8a4ebSJames Feist 
1477acc8a4ebSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1478acc8a4ebSJames Feist {
1479acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1480acc8a4ebSJames Feist     if (data.empty())
1481acc8a4ebSJames Feist     {
1482acc8a4ebSJames Feist         return ipmi::responseResponseError();
1483acc8a4ebSJames Feist     }
1484acc8a4ebSJames Feist     uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1485acc8a4ebSJames Feist     for (const auto& [_, pid] : data)
1486acc8a4ebSJames Feist     {
1487acc8a4ebSJames Feist         auto findClass = pid.find("Class");
1488acc8a4ebSJames Feist         if (findClass == pid.end())
1489acc8a4ebSJames Feist         {
1490acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1491acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: found illegal pid "
1492acc8a4ebSJames Feist                 "configurations");
1493acc8a4ebSJames Feist             return ipmi::responseResponseError();
1494acc8a4ebSJames Feist         }
1495acc8a4ebSJames Feist         std::string type = std::get<std::string>(findClass->second);
1496acc8a4ebSJames Feist         if (type == "fan")
1497acc8a4ebSJames Feist         {
1498acc8a4ebSJames Feist             auto findOutLimit = pid.find("OutLimitMin");
1499acc8a4ebSJames Feist             if (findOutLimit == pid.end())
1500acc8a4ebSJames Feist             {
1501acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1502acc8a4ebSJames Feist                     "ipmiOEMGetFscParameter: found illegal pid "
1503acc8a4ebSJames Feist                     "configurations");
1504acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1505acc8a4ebSJames Feist             }
1506acc8a4ebSJames Feist             // get the min out of all the offsets
1507acc8a4ebSJames Feist             minOffset = std::min(
1508acc8a4ebSJames Feist                 minOffset,
1509acc8a4ebSJames Feist                 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1510acc8a4ebSJames Feist         }
1511acc8a4ebSJames Feist     }
1512acc8a4ebSJames Feist     if (minOffset == std::numeric_limits<uint8_t>::max())
1513acc8a4ebSJames Feist     {
1514acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1515acc8a4ebSJames Feist             "ipmiOEMGetFscParameter: found no fan configurations!");
1516acc8a4ebSJames Feist         return ipmi::responseResponseError();
1517acc8a4ebSJames Feist     }
1518acc8a4ebSJames Feist 
1519acc8a4ebSJames Feist     return ipmi::responseSuccess(minOffset);
1520acc8a4ebSJames Feist }
1521acc8a4ebSJames Feist 
1522acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1523acc8a4ebSJames Feist {
1524acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1525acc8a4ebSJames Feist     if (data.empty())
1526acc8a4ebSJames Feist     {
1527acc8a4ebSJames Feist 
1528acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1529acc8a4ebSJames Feist             "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1530acc8a4ebSJames Feist         return ipmi::responseResponseError();
1531acc8a4ebSJames Feist     }
1532acc8a4ebSJames Feist 
153315419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1534acc8a4ebSJames Feist     bool found = false;
1535acc8a4ebSJames Feist     for (const auto& [path, pid] : data)
1536acc8a4ebSJames Feist     {
1537acc8a4ebSJames Feist         auto findClass = pid.find("Class");
1538acc8a4ebSJames Feist         if (findClass == pid.end())
1539acc8a4ebSJames Feist         {
1540acc8a4ebSJames Feist 
1541acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1542acc8a4ebSJames Feist                 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1543acc8a4ebSJames Feist                 "configurations");
1544acc8a4ebSJames Feist             return ipmi::responseResponseError();
1545acc8a4ebSJames Feist         }
1546acc8a4ebSJames Feist         std::string type = std::get<std::string>(findClass->second);
1547acc8a4ebSJames Feist         if (type == "fan")
1548acc8a4ebSJames Feist         {
1549acc8a4ebSJames Feist             auto findOutLimit = pid.find("OutLimitMin");
1550acc8a4ebSJames Feist             if (findOutLimit == pid.end())
1551acc8a4ebSJames Feist             {
1552acc8a4ebSJames Feist 
1553acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1554acc8a4ebSJames Feist                     "ipmiOEMSetFanSpeedOffset: found illegal pid "
1555acc8a4ebSJames Feist                     "configurations");
1556acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1557acc8a4ebSJames Feist             }
155815419dd5SVernon Mauery             ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
1559acc8a4ebSJames Feist                                   path, pidConfigurationIface, "OutLimitMin",
1560acc8a4ebSJames Feist                                   static_cast<double>(offset));
1561acc8a4ebSJames Feist             found = true;
1562acc8a4ebSJames Feist         }
1563acc8a4ebSJames Feist     }
1564acc8a4ebSJames Feist     if (!found)
1565acc8a4ebSJames Feist     {
1566acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1567acc8a4ebSJames Feist             "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1568acc8a4ebSJames Feist         return ipmi::responseResponseError();
1569acc8a4ebSJames Feist     }
1570acc8a4ebSJames Feist 
1571acc8a4ebSJames Feist     return ipmi::responseSuccess();
1572acc8a4ebSJames Feist }
1573acc8a4ebSJames Feist 
1574acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1575acc8a4ebSJames Feist                                        uint8_t param2)
15765f957cafSJames Feist {
15775f957cafSJames Feist     constexpr const size_t disableLimiting = 0x0;
15785f957cafSJames Feist 
157915419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1580acc8a4ebSJames Feist     if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
15815f957cafSJames Feist     {
158209f6b604SJames Feist         std::string pathName;
1583acc8a4ebSJames Feist         if (param1 == legacyExitAirSensorNumber)
1584faa4f223SJames Feist         {
158509f6b604SJames Feist             pathName = exitAirPathName;
158609f6b604SJames Feist         }
158709f6b604SJames Feist         else if (param1 == legacyPCHSensorNumber)
158809f6b604SJames Feist         {
158909f6b604SJames Feist             pathName = pchPathName;
1590faa4f223SJames Feist         }
1591faa4f223SJames Feist         else
1592faa4f223SJames Feist         {
1593acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
1594faa4f223SJames Feist         }
159509f6b604SJames Feist         std::string path = getConfigPath(pathName);
159609f6b604SJames Feist         ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
159709f6b604SJames Feist                               pidConfigurationIface, "SetPoint",
159809f6b604SJames Feist                               static_cast<double>(param2));
159909f6b604SJames Feist         return ipmi::responseSuccess();
1600faa4f223SJames Feist     }
1601acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
16025f957cafSJames Feist     {
1603acc8a4ebSJames Feist         uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
16045f957cafSJames Feist 
16055f957cafSJames Feist         // must be greater than 50 based on eps
16065f957cafSJames Feist         if (cfm < 50 && cfm != disableLimiting)
16075f957cafSJames Feist         {
1608acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
16095f957cafSJames Feist         }
16105f957cafSJames Feist 
16115f957cafSJames Feist         try
16125f957cafSJames Feist         {
161315419dd5SVernon Mauery             ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
16145f957cafSJames Feist                                   cfmLimitIface, "Limit",
16155f957cafSJames Feist                                   static_cast<double>(cfm));
16165f957cafSJames Feist         }
16175f957cafSJames Feist         catch (sdbusplus::exception_t& e)
16185f957cafSJames Feist         {
16195f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
16205f957cafSJames Feist                 "ipmiOEMSetFscParameter: can't set cfm setting!",
16215f957cafSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
1622acc8a4ebSJames Feist             return ipmi::responseResponseError();
16235f957cafSJames Feist         }
1624acc8a4ebSJames Feist         return ipmi::responseSuccess();
1625acc8a4ebSJames Feist     }
1626acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1627acc8a4ebSJames Feist     {
1628acc8a4ebSJames Feist         constexpr const size_t maxDomainCount = 8;
1629acc8a4ebSJames Feist         uint8_t requestedDomainMask = param1;
1630acc8a4ebSJames Feist         boost::container::flat_map data = getPidConfigs();
1631acc8a4ebSJames Feist         if (data.empty())
1632acc8a4ebSJames Feist         {
1633acc8a4ebSJames Feist 
1634acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1635acc8a4ebSJames Feist                 "ipmiOEMSetFscParameter: found no pid configurations!");
1636acc8a4ebSJames Feist             return ipmi::responseResponseError();
1637acc8a4ebSJames Feist         }
1638acc8a4ebSJames Feist         size_t count = 0;
1639acc8a4ebSJames Feist         for (const auto& [path, pid] : data)
1640acc8a4ebSJames Feist         {
1641acc8a4ebSJames Feist             auto findClass = pid.find("Class");
1642acc8a4ebSJames Feist             if (findClass == pid.end())
1643acc8a4ebSJames Feist             {
1644acc8a4ebSJames Feist 
1645acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1646acc8a4ebSJames Feist                     "ipmiOEMSetFscParameter: found illegal pid "
1647acc8a4ebSJames Feist                     "configurations");
1648acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1649acc8a4ebSJames Feist             }
1650acc8a4ebSJames Feist             std::string type = std::get<std::string>(findClass->second);
1651acc8a4ebSJames Feist             if (type == "fan")
1652acc8a4ebSJames Feist             {
1653acc8a4ebSJames Feist                 if (requestedDomainMask & (1 << count))
1654acc8a4ebSJames Feist                 {
1655acc8a4ebSJames Feist                     ipmi::setDbusProperty(
165615419dd5SVernon Mauery                         *dbus, "xyz.openbmc_project.EntityManager", path,
1657acc8a4ebSJames Feist                         pidConfigurationIface, "OutLimitMax",
1658acc8a4ebSJames Feist                         static_cast<double>(param2));
1659acc8a4ebSJames Feist                 }
1660acc8a4ebSJames Feist                 count++;
1661acc8a4ebSJames Feist             }
1662acc8a4ebSJames Feist         }
1663acc8a4ebSJames Feist         return ipmi::responseSuccess();
16645f957cafSJames Feist     }
16655f957cafSJames Feist     else
16665f957cafSJames Feist     {
16675f957cafSJames Feist         // todo other command parts possibly
16685f957cafSJames Feist         // tcontrol is handled in peci now
16695f957cafSJames Feist         // fan speed offset not implemented yet
16705f957cafSJames Feist         // domain pwm limit not implemented
1671acc8a4ebSJames Feist         return ipmi::responseParmOutOfRange();
16725f957cafSJames Feist     }
16735f957cafSJames Feist }
16745f957cafSJames Feist 
1675acc8a4ebSJames Feist ipmi::RspType<
1676acc8a4ebSJames Feist     std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1677acc8a4ebSJames Feist     ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
16785f957cafSJames Feist {
167909f6b604SJames Feist     constexpr uint8_t legacyDefaultSetpoint = -128;
16805f957cafSJames Feist 
168115419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1682acc8a4ebSJames Feist     if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
16835f957cafSJames Feist     {
1684acc8a4ebSJames Feist         if (!param)
1685acc8a4ebSJames Feist         {
1686acc8a4ebSJames Feist             return ipmi::responseReqDataLenInvalid();
16875f957cafSJames Feist         }
16885f957cafSJames Feist 
168909f6b604SJames Feist         std::string pathName;
169009f6b604SJames Feist 
169109f6b604SJames Feist         if (*param == legacyExitAirSensorNumber)
169209f6b604SJames Feist         {
169309f6b604SJames Feist             pathName = exitAirPathName;
169409f6b604SJames Feist         }
169509f6b604SJames Feist         else if (*param == legacyPCHSensorNumber)
169609f6b604SJames Feist         {
169709f6b604SJames Feist             pathName = pchPathName;
169809f6b604SJames Feist         }
169909f6b604SJames Feist         else
1700faa4f223SJames Feist         {
1701acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
1702faa4f223SJames Feist         }
170309f6b604SJames Feist 
170409f6b604SJames Feist         uint8_t setpoint = legacyDefaultSetpoint;
170509f6b604SJames Feist         std::string path = getConfigPath(pathName);
1706faa4f223SJames Feist         if (path.size())
1707faa4f223SJames Feist         {
170815419dd5SVernon Mauery             Value val = ipmi::getDbusProperty(
170915419dd5SVernon Mauery                 *dbus, "xyz.openbmc_project.EntityManager", path,
171015419dd5SVernon Mauery                 pidConfigurationIface, "SetPoint");
1711faa4f223SJames Feist             setpoint = std::floor(std::get<double>(val) + 0.5);
1712faa4f223SJames Feist         }
1713faa4f223SJames Feist 
1714faa4f223SJames Feist         // old implementation used to return the "default" and current, we
1715faa4f223SJames Feist         // don't make the default readily available so just make both the
1716faa4f223SJames Feist         // same
1717faa4f223SJames Feist 
1718acc8a4ebSJames Feist         return ipmi::responseSuccess(
1719acc8a4ebSJames Feist             std::array<uint8_t, 2>{setpoint, setpoint});
1720faa4f223SJames Feist     }
1721acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1722acc8a4ebSJames Feist     {
1723acc8a4ebSJames Feist         constexpr const size_t maxDomainCount = 8;
1724acc8a4ebSJames Feist 
1725acc8a4ebSJames Feist         if (!param)
1726acc8a4ebSJames Feist         {
1727acc8a4ebSJames Feist             return ipmi::responseReqDataLenInvalid();
1728acc8a4ebSJames Feist         }
1729acc8a4ebSJames Feist         uint8_t requestedDomain = *param;
1730acc8a4ebSJames Feist         if (requestedDomain >= maxDomainCount)
1731acc8a4ebSJames Feist         {
1732acc8a4ebSJames Feist             return ipmi::responseInvalidFieldRequest();
1733acc8a4ebSJames Feist         }
1734acc8a4ebSJames Feist 
1735acc8a4ebSJames Feist         boost::container::flat_map data = getPidConfigs();
1736acc8a4ebSJames Feist         if (data.empty())
1737acc8a4ebSJames Feist         {
1738acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1739acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: found no pid configurations!");
1740acc8a4ebSJames Feist             return ipmi::responseResponseError();
1741acc8a4ebSJames Feist         }
1742acc8a4ebSJames Feist         size_t count = 0;
1743acc8a4ebSJames Feist         for (const auto& [_, pid] : data)
1744acc8a4ebSJames Feist         {
1745acc8a4ebSJames Feist             auto findClass = pid.find("Class");
1746acc8a4ebSJames Feist             if (findClass == pid.end())
1747acc8a4ebSJames Feist             {
1748acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1749acc8a4ebSJames Feist                     "ipmiOEMGetFscParameter: found illegal pid "
1750acc8a4ebSJames Feist                     "configurations");
1751acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1752acc8a4ebSJames Feist             }
1753acc8a4ebSJames Feist             std::string type = std::get<std::string>(findClass->second);
1754acc8a4ebSJames Feist             if (type == "fan")
1755acc8a4ebSJames Feist             {
1756acc8a4ebSJames Feist                 if (requestedDomain == count)
1757acc8a4ebSJames Feist                 {
1758acc8a4ebSJames Feist                     auto findOutLimit = pid.find("OutLimitMax");
1759acc8a4ebSJames Feist                     if (findOutLimit == pid.end())
1760acc8a4ebSJames Feist                     {
1761acc8a4ebSJames Feist                         phosphor::logging::log<phosphor::logging::level::ERR>(
1762acc8a4ebSJames Feist                             "ipmiOEMGetFscParameter: found illegal pid "
1763acc8a4ebSJames Feist                             "configurations");
1764acc8a4ebSJames Feist                         return ipmi::responseResponseError();
1765acc8a4ebSJames Feist                     }
1766acc8a4ebSJames Feist 
1767acc8a4ebSJames Feist                     return ipmi::responseSuccess(
1768acc8a4ebSJames Feist                         static_cast<uint8_t>(std::floor(
1769acc8a4ebSJames Feist                             std::get<double>(findOutLimit->second) + 0.5)));
1770acc8a4ebSJames Feist                 }
1771acc8a4ebSJames Feist                 else
1772acc8a4ebSJames Feist                 {
1773acc8a4ebSJames Feist                     count++;
1774acc8a4ebSJames Feist                 }
1775acc8a4ebSJames Feist             }
1776acc8a4ebSJames Feist         }
1777acc8a4ebSJames Feist 
1778acc8a4ebSJames Feist         return ipmi::responseInvalidFieldRequest();
1779acc8a4ebSJames Feist     }
1780acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
17815f957cafSJames Feist     {
17825f957cafSJames Feist 
17835f957cafSJames Feist         /*
17845f957cafSJames Feist         DataLen should be 1, but host is sending us an extra bit. As the
1785acc8a4ebSJames Feist         previous behavior didn't seem to prevent this, ignore the check for
1786acc8a4ebSJames Feist         now.
17875f957cafSJames Feist 
1788acc8a4ebSJames Feist         if (param)
17895f957cafSJames Feist         {
17905f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
17915f957cafSJames Feist                 "ipmiOEMGetFscParameter: invalid input len!");
17925f957cafSJames Feist             return IPMI_CC_REQ_DATA_LEN_INVALID;
17935f957cafSJames Feist         }
17945f957cafSJames Feist         */
17955f957cafSJames Feist         Value cfmLimit;
17965f957cafSJames Feist         Value cfmMaximum;
17975f957cafSJames Feist         try
17985f957cafSJames Feist         {
179915419dd5SVernon Mauery             cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
18005f957cafSJames Feist                                              cfmLimitSettingPath, cfmLimitIface,
18015f957cafSJames Feist                                              "Limit");
18025f957cafSJames Feist             cfmMaximum = ipmi::getDbusProperty(
180315419dd5SVernon Mauery                 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
18045f957cafSJames Feist                 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
18055f957cafSJames Feist         }
18065f957cafSJames Feist         catch (sdbusplus::exception_t& e)
18075f957cafSJames Feist         {
18085f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1809acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: can't get cfm setting!",
18105f957cafSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
1811acc8a4ebSJames Feist             return ipmi::responseResponseError();
18125f957cafSJames Feist         }
18135f957cafSJames Feist 
1814acc8a4ebSJames Feist         double cfmMax = std::get<double>(cfmMaximum);
1815acc8a4ebSJames Feist         double cfmLim = std::get<double>(cfmLimit);
1816acc8a4ebSJames Feist 
1817acc8a4ebSJames Feist         cfmLim = std::floor(cfmLim + 0.5);
1818acc8a4ebSJames Feist         cfmMax = std::floor(cfmMax + 0.5);
1819acc8a4ebSJames Feist         uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1820acc8a4ebSJames Feist         uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
1821acc8a4ebSJames Feist 
1822acc8a4ebSJames Feist         return ipmi::responseSuccess(
1823acc8a4ebSJames Feist             std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
18245f957cafSJames Feist     }
18255f957cafSJames Feist 
18265f957cafSJames Feist     else
18275f957cafSJames Feist     {
18285f957cafSJames Feist         // todo other command parts possibly
18295f957cafSJames Feist         // domain pwm limit not implemented
1830acc8a4ebSJames Feist         return ipmi::responseParmOutOfRange();
18315f957cafSJames Feist     }
18325f957cafSJames Feist }
18335f957cafSJames Feist 
1834773703a5SCheng C Yang using crConfigVariant =
1835773703a5SCheng C Yang     std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
1836773703a5SCheng C Yang 
1837773703a5SCheng C Yang int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1838773703a5SCheng C Yang                 const crConfigVariant& value,
1839773703a5SCheng C Yang                 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1840773703a5SCheng C Yang {
1841773703a5SCheng C Yang     boost::system::error_code ec;
1842773703a5SCheng C Yang     ctx->bus->yield_method_call<void>(
184328c7290cSJames Feist         ctx->yield, ec, "xyz.openbmc_project.Settings",
1844773703a5SCheng C Yang         "/xyz/openbmc_project/control/power_supply_redundancy",
1845773703a5SCheng C Yang         "org.freedesktop.DBus.Properties", "Set",
1846773703a5SCheng C Yang         "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
1847773703a5SCheng C Yang     if (ec)
1848773703a5SCheng C Yang     {
1849773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
1850773703a5SCheng C Yang             "Failed to set dbus property to cold redundancy");
1851773703a5SCheng C Yang         return -1;
1852773703a5SCheng C Yang     }
1853773703a5SCheng C Yang 
1854773703a5SCheng C Yang     return 0;
1855773703a5SCheng C Yang }
1856773703a5SCheng C Yang 
1857773703a5SCheng C Yang int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1858773703a5SCheng C Yang                 crConfigVariant& value,
1859773703a5SCheng C Yang                 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1860773703a5SCheng C Yang {
1861773703a5SCheng C Yang     boost::system::error_code ec;
1862773703a5SCheng C Yang     value = ctx->bus->yield_method_call<crConfigVariant>(
186328c7290cSJames Feist         ctx->yield, ec, "xyz.openbmc_project.Settings",
1864773703a5SCheng C Yang         "/xyz/openbmc_project/control/power_supply_redundancy",
1865773703a5SCheng C Yang         "org.freedesktop.DBus.Properties", "Get",
1866773703a5SCheng C Yang         "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
1867773703a5SCheng C Yang     if (ec)
1868773703a5SCheng C Yang     {
1869773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
1870773703a5SCheng C Yang             "Failed to get dbus property to cold redundancy");
1871773703a5SCheng C Yang         return -1;
1872773703a5SCheng C Yang     }
1873773703a5SCheng C Yang     return 0;
1874773703a5SCheng C Yang }
1875773703a5SCheng C Yang 
1876773703a5SCheng C Yang uint8_t getPSUCount(void)
1877773703a5SCheng C Yang {
1878773703a5SCheng C Yang     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1879773703a5SCheng C Yang     ipmi::Value num;
1880773703a5SCheng C Yang     try
1881773703a5SCheng C Yang     {
1882773703a5SCheng C Yang         num = ipmi::getDbusProperty(
1883773703a5SCheng C Yang             *dbus, "xyz.openbmc_project.PSURedundancy",
1884773703a5SCheng C Yang             "/xyz/openbmc_project/control/power_supply_redundancy",
1885773703a5SCheng C Yang             "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
1886773703a5SCheng C Yang     }
1887773703a5SCheng C Yang     catch (sdbusplus::exception_t& e)
1888773703a5SCheng C Yang     {
1889773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
1890773703a5SCheng C Yang             "Failed to get PSUNumber property from dbus interface");
1891773703a5SCheng C Yang         return 0;
1892773703a5SCheng C Yang     }
1893773703a5SCheng C Yang     uint8_t* pNum = std::get_if<uint8_t>(&num);
1894773703a5SCheng C Yang     if (!pNum)
1895773703a5SCheng C Yang     {
1896773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
1897773703a5SCheng C Yang             "Error to get PSU Number");
1898773703a5SCheng C Yang         return 0;
1899773703a5SCheng C Yang     }
1900773703a5SCheng C Yang     return *pNum;
1901773703a5SCheng C Yang }
1902773703a5SCheng C Yang 
1903773703a5SCheng C Yang bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
1904773703a5SCheng C Yang {
1905773703a5SCheng C Yang     if (conf.size() < num)
1906773703a5SCheng C Yang     {
1907773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
1908773703a5SCheng C Yang             "Invalid PSU Ranking");
1909773703a5SCheng C Yang         return false;
1910773703a5SCheng C Yang     }
1911773703a5SCheng C Yang     std::set<uint8_t> confSet;
1912773703a5SCheng C Yang     for (uint8_t i = 0; i < num; i++)
1913773703a5SCheng C Yang     {
1914773703a5SCheng C Yang         if (conf[i] > num)
1915773703a5SCheng C Yang         {
1916773703a5SCheng C Yang             phosphor::logging::log<phosphor::logging::level::ERR>(
1917773703a5SCheng C Yang                 "PSU Ranking is larger than current PSU number");
1918773703a5SCheng C Yang             return false;
1919773703a5SCheng C Yang         }
1920773703a5SCheng C Yang         confSet.emplace(conf[i]);
1921773703a5SCheng C Yang     }
1922773703a5SCheng C Yang 
1923773703a5SCheng C Yang     if (confSet.size() != num)
1924773703a5SCheng C Yang     {
1925773703a5SCheng C Yang         phosphor::logging::log<phosphor::logging::level::ERR>(
1926773703a5SCheng C Yang             "duplicate PSU Ranking");
1927773703a5SCheng C Yang         return false;
1928773703a5SCheng C Yang     }
1929773703a5SCheng C Yang     return true;
1930773703a5SCheng C Yang }
1931773703a5SCheng C Yang 
1932773703a5SCheng C Yang enum class crParameter
1933773703a5SCheng C Yang {
1934773703a5SCheng C Yang     crStatus = 0,
1935773703a5SCheng C Yang     crFeature = 1,
1936773703a5SCheng C Yang     rotationFeature = 2,
1937773703a5SCheng C Yang     rotationAlgo = 3,
1938773703a5SCheng C Yang     rotationPeriod = 4,
1939773703a5SCheng C Yang     numOfPSU = 5
1940773703a5SCheng C Yang };
1941773703a5SCheng C Yang 
1942773703a5SCheng C Yang constexpr ipmi::Cc ccParameterNotSupported = 0x80;
1943773703a5SCheng C Yang static const constexpr uint32_t oneDay = 0x15180;
1944773703a5SCheng C Yang static const constexpr uint32_t oneMonth = 0xf53700;
1945773703a5SCheng C Yang static const constexpr uint8_t userSpecific = 0x01;
1946773703a5SCheng C Yang static const constexpr uint8_t crSetCompleted = 0;
1947773703a5SCheng C Yang ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
1948773703a5SCheng C Yang                                           uint8_t parameter,
1949773703a5SCheng C Yang                                           ipmi::message::Payload& payload)
1950773703a5SCheng C Yang {
1951773703a5SCheng C Yang     switch (static_cast<crParameter>(parameter))
1952773703a5SCheng C Yang     {
1953773703a5SCheng C Yang         case crParameter::crFeature:
1954773703a5SCheng C Yang         {
1955773703a5SCheng C Yang             uint8_t param1;
1956773703a5SCheng C Yang             if (payload.unpack(param1) || !payload.fullyUnpacked())
1957773703a5SCheng C Yang             {
1958773703a5SCheng C Yang                 return ipmi::responseReqDataLenInvalid();
1959773703a5SCheng C Yang             }
1960773703a5SCheng C Yang             // ColdRedundancy Enable can only be true or flase
1961773703a5SCheng C Yang             if (param1 > 1)
1962773703a5SCheng C Yang             {
1963773703a5SCheng C Yang                 return ipmi::responseInvalidFieldRequest();
1964773703a5SCheng C Yang             }
1965773703a5SCheng C Yang             if (setCRConfig(ctx, "ColdRedundancyEnabled",
1966773703a5SCheng C Yang                             static_cast<bool>(param1)))
1967773703a5SCheng C Yang             {
1968773703a5SCheng C Yang                 return ipmi::responseResponseError();
1969773703a5SCheng C Yang             }
1970773703a5SCheng C Yang             break;
1971773703a5SCheng C Yang         }
1972773703a5SCheng C Yang         case crParameter::rotationFeature:
1973773703a5SCheng C Yang         {
1974773703a5SCheng C Yang             uint8_t param1;
1975773703a5SCheng C Yang             if (payload.unpack(param1) || !payload.fullyUnpacked())
1976773703a5SCheng C Yang             {
1977773703a5SCheng C Yang                 return ipmi::responseReqDataLenInvalid();
1978773703a5SCheng C Yang             }
1979773703a5SCheng C Yang             // Rotation Enable can only be true or false
1980773703a5SCheng C Yang             if (param1 > 1)
1981773703a5SCheng C Yang             {
1982773703a5SCheng C Yang                 return ipmi::responseInvalidFieldRequest();
1983773703a5SCheng C Yang             }
1984773703a5SCheng C Yang             if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
1985773703a5SCheng C Yang             {
1986773703a5SCheng C Yang                 return ipmi::responseResponseError();
1987773703a5SCheng C Yang             }
1988773703a5SCheng C Yang             break;
1989773703a5SCheng C Yang         }
1990773703a5SCheng C Yang         case crParameter::rotationAlgo:
1991773703a5SCheng C Yang         {
1992773703a5SCheng C Yang             // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
1993773703a5SCheng C Yang             std::string algoName;
1994773703a5SCheng C Yang             uint8_t param1;
1995773703a5SCheng C Yang             if (payload.unpack(param1))
1996773703a5SCheng C Yang             {
1997773703a5SCheng C Yang                 return ipmi::responseReqDataLenInvalid();
1998773703a5SCheng C Yang             }
1999773703a5SCheng C Yang             switch (param1)
2000773703a5SCheng C Yang             {
2001773703a5SCheng C Yang                 case 0:
2002773703a5SCheng C Yang                     algoName = "xyz.openbmc_project.Control."
2003773703a5SCheng C Yang                                "PowerSupplyRedundancy.Algo.bmcSpecific";
2004773703a5SCheng C Yang                     break;
2005773703a5SCheng C Yang                 case 1:
2006773703a5SCheng C Yang                     algoName = "xyz.openbmc_project.Control."
2007773703a5SCheng C Yang                                "PowerSupplyRedundancy.Algo.userSpecific";
2008773703a5SCheng C Yang                     break;
2009773703a5SCheng C Yang                 default:
2010773703a5SCheng C Yang                     return ipmi::responseInvalidFieldRequest();
2011773703a5SCheng C Yang             }
2012773703a5SCheng C Yang             if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2013773703a5SCheng C Yang             {
2014773703a5SCheng C Yang                 return ipmi::responseResponseError();
2015773703a5SCheng C Yang             }
2016773703a5SCheng C Yang 
2017773703a5SCheng C Yang             uint8_t numberOfPSU = getPSUCount();
2018773703a5SCheng C Yang             if (!numberOfPSU)
2019773703a5SCheng C Yang             {
2020773703a5SCheng C Yang                 return ipmi::responseResponseError();
2021773703a5SCheng C Yang             }
2022773703a5SCheng C Yang             std::vector<uint8_t> rankOrder;
2023773703a5SCheng C Yang 
2024773703a5SCheng C Yang             if (param1 == userSpecific)
2025773703a5SCheng C Yang             {
2026773703a5SCheng C Yang                 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2027773703a5SCheng C Yang                 {
2028773703a5SCheng C Yang                     ipmi::responseReqDataLenInvalid();
2029773703a5SCheng C Yang                 }
2030773703a5SCheng C Yang                 if (rankOrder.size() < numberOfPSU)
2031773703a5SCheng C Yang                 {
2032773703a5SCheng C Yang                     return ipmi::responseReqDataLenInvalid();
2033773703a5SCheng C Yang                 }
2034773703a5SCheng C Yang 
2035773703a5SCheng C Yang                 if (!validateCRAlgo(rankOrder, numberOfPSU))
2036773703a5SCheng C Yang                 {
2037773703a5SCheng C Yang                     return ipmi::responseInvalidFieldRequest();
2038773703a5SCheng C Yang                 }
2039773703a5SCheng C Yang             }
2040773703a5SCheng C Yang             else
2041773703a5SCheng C Yang             {
2042773703a5SCheng C Yang                 if (rankOrder.size() > 0)
2043773703a5SCheng C Yang                 {
2044773703a5SCheng C Yang                     return ipmi::responseReqDataLenInvalid();
2045773703a5SCheng C Yang                 }
2046773703a5SCheng C Yang                 for (uint8_t i = 1; i <= numberOfPSU; i++)
2047773703a5SCheng C Yang                 {
2048773703a5SCheng C Yang                     rankOrder.emplace_back(i);
2049773703a5SCheng C Yang                 }
2050773703a5SCheng C Yang             }
2051773703a5SCheng C Yang             if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2052773703a5SCheng C Yang             {
2053773703a5SCheng C Yang                 return ipmi::responseResponseError();
2054773703a5SCheng C Yang             }
2055773703a5SCheng C Yang             break;
2056773703a5SCheng C Yang         }
2057773703a5SCheng C Yang         case crParameter::rotationPeriod:
2058773703a5SCheng C Yang         {
2059773703a5SCheng C Yang             // Minimum Rotation period is  One day (86400 seconds) and Max
2060773703a5SCheng C Yang             // Rotation Period is 6 month (0xf53700 seconds)
2061773703a5SCheng C Yang             uint32_t period;
2062773703a5SCheng C Yang             if (payload.unpack(period) || !payload.fullyUnpacked())
2063773703a5SCheng C Yang             {
2064773703a5SCheng C Yang                 return ipmi::responseReqDataLenInvalid();
2065773703a5SCheng C Yang             }
2066773703a5SCheng C Yang             if ((period < oneDay) || (period > oneMonth))
2067773703a5SCheng C Yang             {
2068773703a5SCheng C Yang                 return ipmi::responseInvalidFieldRequest();
2069773703a5SCheng C Yang             }
2070773703a5SCheng C Yang             if (setCRConfig(ctx, "PeriodOfRotation", period))
2071773703a5SCheng C Yang             {
2072773703a5SCheng C Yang                 return ipmi::responseResponseError();
2073773703a5SCheng C Yang             }
2074773703a5SCheng C Yang             break;
2075773703a5SCheng C Yang         }
2076773703a5SCheng C Yang         default:
2077773703a5SCheng C Yang         {
2078773703a5SCheng C Yang             return ipmi::response(ccParameterNotSupported);
2079773703a5SCheng C Yang         }
2080773703a5SCheng C Yang     }
2081773703a5SCheng C Yang 
2082773703a5SCheng C Yang     // TODO Halfwidth needs to set SetInProgress
2083773703a5SCheng C Yang     if (setCRConfig(ctx, "ColdRedundancyStatus",
2084e8cecdffSCheng C Yang                     std::string("xyz.openbmc_project.Control."
2085e8cecdffSCheng C Yang                                 "PowerSupplyRedundancy.Status.completed")))
2086773703a5SCheng C Yang     {
2087773703a5SCheng C Yang         return ipmi::responseResponseError();
2088773703a5SCheng C Yang     }
2089773703a5SCheng C Yang     return ipmi::responseSuccess(crSetCompleted);
2090773703a5SCheng C Yang }
2091773703a5SCheng C Yang 
2092f41e334dSCheng C Yang ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::array<uint8_t, 5>>>
2093773703a5SCheng C Yang     ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2094773703a5SCheng C Yang {
2095773703a5SCheng C Yang     crConfigVariant value;
2096773703a5SCheng C Yang     switch (static_cast<crParameter>(parameter))
2097773703a5SCheng C Yang     {
2098773703a5SCheng C Yang         case crParameter::crStatus:
2099773703a5SCheng C Yang         {
2100773703a5SCheng C Yang             if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2101773703a5SCheng C Yang             {
2102773703a5SCheng C Yang                 return ipmi::responseResponseError();
2103773703a5SCheng C Yang             }
2104773703a5SCheng C Yang             std::string* pStatus = std::get_if<std::string>(&value);
2105773703a5SCheng C Yang             if (!pStatus)
2106773703a5SCheng C Yang             {
2107773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2108773703a5SCheng C Yang                     "Error to get ColdRedundancyStatus property");
2109773703a5SCheng C Yang                 return ipmi::responseResponseError();
2110773703a5SCheng C Yang             }
2111773703a5SCheng C Yang             namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2112773703a5SCheng C Yang             auto status =
2113773703a5SCheng C Yang                 server::PowerSupplyRedundancy::convertStatusFromString(
2114773703a5SCheng C Yang                     *pStatus);
2115773703a5SCheng C Yang             switch (status)
2116773703a5SCheng C Yang             {
2117773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Status::inProgress:
2118f41e334dSCheng C Yang                     return ipmi::responseSuccess(parameter,
2119f41e334dSCheng C Yang                                                  static_cast<uint8_t>(0));
2120773703a5SCheng C Yang 
2121773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Status::completed:
2122f41e334dSCheng C Yang                     return ipmi::responseSuccess(parameter,
2123f41e334dSCheng C Yang                                                  static_cast<uint8_t>(1));
2124773703a5SCheng C Yang                 default:
2125773703a5SCheng C Yang                     phosphor::logging::log<phosphor::logging::level::ERR>(
2126773703a5SCheng C Yang                         "Error to get valid status");
2127773703a5SCheng C Yang                     return ipmi::responseResponseError();
2128773703a5SCheng C Yang             }
2129773703a5SCheng C Yang         }
2130773703a5SCheng C Yang         case crParameter::crFeature:
2131773703a5SCheng C Yang         {
2132773703a5SCheng C Yang             if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2133773703a5SCheng C Yang             {
2134773703a5SCheng C Yang                 return ipmi::responseResponseError();
2135773703a5SCheng C Yang             }
2136773703a5SCheng C Yang             bool* pResponse = std::get_if<bool>(&value);
2137773703a5SCheng C Yang             if (!pResponse)
2138773703a5SCheng C Yang             {
2139773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2140773703a5SCheng C Yang                     "Error to get ColdRedundancyEnable property");
2141773703a5SCheng C Yang                 return ipmi::responseResponseError();
2142773703a5SCheng C Yang             }
2143773703a5SCheng C Yang 
2144f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter,
2145f41e334dSCheng C Yang                                          static_cast<uint8_t>(*pResponse));
2146773703a5SCheng C Yang         }
2147773703a5SCheng C Yang         case crParameter::rotationFeature:
2148773703a5SCheng C Yang         {
2149773703a5SCheng C Yang             if (getCRConfig(ctx, "RotationEnabled", value))
2150773703a5SCheng C Yang             {
2151773703a5SCheng C Yang                 return ipmi::responseResponseError();
2152773703a5SCheng C Yang             }
2153773703a5SCheng C Yang             bool* pResponse = std::get_if<bool>(&value);
2154773703a5SCheng C Yang             if (!pResponse)
2155773703a5SCheng C Yang             {
2156773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2157773703a5SCheng C Yang                     "Error to get RotationEnabled property");
2158773703a5SCheng C Yang                 return ipmi::responseResponseError();
2159773703a5SCheng C Yang             }
2160f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter,
2161f41e334dSCheng C Yang                                          static_cast<uint8_t>(*pResponse));
2162773703a5SCheng C Yang         }
2163773703a5SCheng C Yang         case crParameter::rotationAlgo:
2164773703a5SCheng C Yang         {
2165773703a5SCheng C Yang             if (getCRConfig(ctx, "RotationAlgorithm", value))
2166773703a5SCheng C Yang             {
2167773703a5SCheng C Yang                 return ipmi::responseResponseError();
2168773703a5SCheng C Yang             }
2169773703a5SCheng C Yang 
2170773703a5SCheng C Yang             std::string* pAlgo = std::get_if<std::string>(&value);
2171773703a5SCheng C Yang             if (!pAlgo)
2172773703a5SCheng C Yang             {
2173773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2174773703a5SCheng C Yang                     "Error to get RotationAlgorithm property");
2175773703a5SCheng C Yang                 return ipmi::responseResponseError();
2176773703a5SCheng C Yang             }
2177773703a5SCheng C Yang             std::array<uint8_t, 5> response = {0, 0, 0, 0, 0};
2178773703a5SCheng C Yang             namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2179773703a5SCheng C Yang             auto algo =
2180773703a5SCheng C Yang                 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
2181773703a5SCheng C Yang             switch (algo)
2182773703a5SCheng C Yang             {
2183773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
2184773703a5SCheng C Yang                     response[0] = 0;
2185773703a5SCheng C Yang                     break;
2186773703a5SCheng C Yang                 case server::PowerSupplyRedundancy::Algo::userSpecific:
2187773703a5SCheng C Yang                     response[0] = 1;
2188773703a5SCheng C Yang                     break;
2189773703a5SCheng C Yang                 default:
2190773703a5SCheng C Yang                     phosphor::logging::log<phosphor::logging::level::ERR>(
2191773703a5SCheng C Yang                         "Error to get valid algo");
2192773703a5SCheng C Yang                     return ipmi::responseResponseError();
2193773703a5SCheng C Yang             }
2194773703a5SCheng C Yang 
2195773703a5SCheng C Yang             if (getCRConfig(ctx, "RotationRankOrder", value))
2196773703a5SCheng C Yang             {
2197773703a5SCheng C Yang                 return ipmi::responseResponseError();
2198773703a5SCheng C Yang             }
2199773703a5SCheng C Yang             std::vector<uint8_t>* pResponse =
2200773703a5SCheng C Yang                 std::get_if<std::vector<uint8_t>>(&value);
2201773703a5SCheng C Yang             if (!pResponse)
2202773703a5SCheng C Yang             {
2203773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2204773703a5SCheng C Yang                     "Error to get RotationRankOrder property");
2205773703a5SCheng C Yang                 return ipmi::responseResponseError();
2206773703a5SCheng C Yang             }
2207773703a5SCheng C Yang             if (pResponse->size() + 1 > response.size())
2208773703a5SCheng C Yang             {
2209773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2210773703a5SCheng C Yang                     "Incorrect size of RotationAlgorithm property");
2211773703a5SCheng C Yang                 return ipmi::responseResponseError();
2212773703a5SCheng C Yang             }
2213773703a5SCheng C Yang             std::copy(pResponse->begin(), pResponse->end(),
2214773703a5SCheng C Yang                       response.begin() + 1);
2215f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter, response);
2216773703a5SCheng C Yang         }
2217773703a5SCheng C Yang         case crParameter::rotationPeriod:
2218773703a5SCheng C Yang         {
2219773703a5SCheng C Yang             if (getCRConfig(ctx, "PeriodOfRotation", value))
2220773703a5SCheng C Yang             {
2221773703a5SCheng C Yang                 return ipmi::responseResponseError();
2222773703a5SCheng C Yang             }
2223773703a5SCheng C Yang             uint32_t* pResponse = std::get_if<uint32_t>(&value);
2224773703a5SCheng C Yang             if (!pResponse)
2225773703a5SCheng C Yang             {
2226773703a5SCheng C Yang                 phosphor::logging::log<phosphor::logging::level::ERR>(
2227773703a5SCheng C Yang                     "Error to get RotationAlgorithm property");
2228773703a5SCheng C Yang                 return ipmi::responseResponseError();
2229773703a5SCheng C Yang             }
2230f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter, *pResponse);
2231773703a5SCheng C Yang         }
2232773703a5SCheng C Yang         case crParameter::numOfPSU:
2233773703a5SCheng C Yang         {
2234773703a5SCheng C Yang             uint8_t numberOfPSU = getPSUCount();
2235773703a5SCheng C Yang             if (!numberOfPSU)
2236773703a5SCheng C Yang             {
2237773703a5SCheng C Yang                 return ipmi::responseResponseError();
2238773703a5SCheng C Yang             }
2239f41e334dSCheng C Yang             return ipmi::responseSuccess(parameter, numberOfPSU);
2240773703a5SCheng C Yang         }
2241773703a5SCheng C Yang         default:
2242773703a5SCheng C Yang         {
2243773703a5SCheng C Yang             return ipmi::response(ccParameterNotSupported);
2244773703a5SCheng C Yang         }
2245773703a5SCheng C Yang     }
2246773703a5SCheng C Yang }
2247773703a5SCheng C Yang 
2248be560b09SZhu, Yunge ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2249be560b09SZhu, Yunge                                           uint8_t faultState,
2250be560b09SZhu, Yunge                                           uint8_t faultGroup,
2251be560b09SZhu, Yunge                                           std::array<uint8_t, 8>& ledStateData)
2252be560b09SZhu, Yunge {
2253be560b09SZhu, Yunge     static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2254be560b09SZhu, Yunge     static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2255be560b09SZhu, Yunge     constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2256be560b09SZhu, Yunge     static const std::array<std::string, maxFaultType> faultNames = {
2257be560b09SZhu, Yunge         "faultFan",       "faultTemp",     "faultPower",
2258be560b09SZhu, Yunge         "faultDriveSlot", "faultSoftware", "faultMemory"};
2259be560b09SZhu, Yunge     static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2260be560b09SZhu, Yunge     static constexpr const char* postfixValue = "/value";
2261be560b09SZhu, Yunge 
2262be560b09SZhu, Yunge     constexpr uint8_t maxFaultSource = 0x4;
2263be560b09SZhu, Yunge     constexpr uint8_t skipLEDs = 0xFF;
2264be560b09SZhu, Yunge     constexpr uint8_t pinSize = 64;
2265be560b09SZhu, Yunge     constexpr uint8_t groupSize = 16;
2266be560b09SZhu, Yunge 
2267be560b09SZhu, Yunge     std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2268be560b09SZhu, Yunge     uint64_t resFIndex = 0;
2269be560b09SZhu, Yunge     std::string resFType;
2270be560b09SZhu, Yunge     std::string service;
2271be560b09SZhu, Yunge     ObjectValueTree valueTree;
2272be560b09SZhu, Yunge 
2273be560b09SZhu, Yunge     // Validate the source, fault type
2274be560b09SZhu, Yunge     if ((sourceId >= maxFaultSource) ||
2275be560b09SZhu, Yunge         (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2276be560b09SZhu, Yunge         (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2277be560b09SZhu, Yunge         (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2278be560b09SZhu, Yunge     {
2279be560b09SZhu, Yunge         return ipmi::responseParmOutOfRange();
2280be560b09SZhu, Yunge     }
2281be560b09SZhu, Yunge 
228215419dd5SVernon Mauery     std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2283be560b09SZhu, Yunge     try
2284be560b09SZhu, Yunge     {
228515419dd5SVernon Mauery         service = getService(*dbus, intf, objpath);
228615419dd5SVernon Mauery         valueTree = getManagedObjects(*dbus, service, "/");
2287be560b09SZhu, Yunge     }
2288be560b09SZhu, Yunge     catch (const std::exception& e)
2289be560b09SZhu, Yunge     {
2290be560b09SZhu, Yunge         phosphor::logging::log<phosphor::logging::level::ERR>(
2291be560b09SZhu, Yunge             "No object implements interface",
2292be560b09SZhu, Yunge             phosphor::logging::entry("SERVICE=%s", service.c_str()),
2293be560b09SZhu, Yunge             phosphor::logging::entry("INTF=%s", intf));
2294be560b09SZhu, Yunge         return ipmi::responseResponseError();
2295be560b09SZhu, Yunge     }
2296be560b09SZhu, Yunge 
2297be560b09SZhu, Yunge     if (valueTree.empty())
2298be560b09SZhu, Yunge     {
2299be560b09SZhu, Yunge         phosphor::logging::log<phosphor::logging::level::ERR>(
2300be560b09SZhu, Yunge             "No object implements interface",
2301be560b09SZhu, Yunge             phosphor::logging::entry("INTF=%s", intf));
2302be560b09SZhu, Yunge         return ipmi::responseResponseError();
2303be560b09SZhu, Yunge     }
2304be560b09SZhu, Yunge 
2305be560b09SZhu, Yunge     for (const auto& item : valueTree)
2306be560b09SZhu, Yunge     {
2307be560b09SZhu, Yunge         // find LedFault configuration
2308be560b09SZhu, Yunge         auto interface =
2309be560b09SZhu, Yunge             item.second.find("xyz.openbmc_project.Configuration.LedFault");
2310be560b09SZhu, Yunge         if (interface == item.second.end())
2311be560b09SZhu, Yunge         {
2312be560b09SZhu, Yunge             continue;
2313be560b09SZhu, Yunge         }
2314be560b09SZhu, Yunge 
2315be560b09SZhu, Yunge         // find matched fault type: faultMemmory / faultFan
2316be560b09SZhu, Yunge         // find LedGpioPins/FaultIndex configuration
2317be560b09SZhu, Yunge         auto propertyFaultType = interface->second.find("FaultType");
2318be560b09SZhu, Yunge         auto propertyFIndex = interface->second.find("FaultIndex");
2319be560b09SZhu, Yunge         auto ledIndex = interface->second.find("LedGpioPins");
2320be560b09SZhu, Yunge 
2321be560b09SZhu, Yunge         if (propertyFaultType == interface->second.end() ||
2322be560b09SZhu, Yunge             propertyFIndex == interface->second.end() ||
2323be560b09SZhu, Yunge             ledIndex == interface->second.end())
2324be560b09SZhu, Yunge         {
2325be560b09SZhu, Yunge             continue;
2326be560b09SZhu, Yunge         }
2327be560b09SZhu, Yunge 
2328be560b09SZhu, Yunge         try
2329be560b09SZhu, Yunge         {
2330be560b09SZhu, Yunge             Value valIndex = propertyFIndex->second;
2331be560b09SZhu, Yunge             resFIndex = std::get<uint64_t>(valIndex);
2332be560b09SZhu, Yunge 
2333be560b09SZhu, Yunge             Value valFType = propertyFaultType->second;
2334be560b09SZhu, Yunge             resFType = std::get<std::string>(valFType);
2335be560b09SZhu, Yunge         }
2336be560b09SZhu, Yunge         catch (const std::bad_variant_access& e)
2337be560b09SZhu, Yunge         {
2338be560b09SZhu, Yunge             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2339be560b09SZhu, Yunge             return ipmi::responseResponseError();
2340be560b09SZhu, Yunge         }
2341be560b09SZhu, Yunge         // find the matched requested fault type: faultMemmory or faultFan
2342be560b09SZhu, Yunge         if (resFType != faultNames[faultType])
2343be560b09SZhu, Yunge         {
2344be560b09SZhu, Yunge             continue;
2345be560b09SZhu, Yunge         }
2346be560b09SZhu, Yunge 
2347be560b09SZhu, Yunge         // read LedGpioPins data
2348be560b09SZhu, Yunge         std::vector<uint64_t> ledgpios;
2349be560b09SZhu, Yunge         std::variant<std::vector<uint64_t>> message;
2350be560b09SZhu, Yunge 
235115419dd5SVernon Mauery         auto method = dbus->new_method_call(
2352be560b09SZhu, Yunge             service.c_str(), (std::string(item.first)).c_str(),
2353be560b09SZhu, Yunge             "org.freedesktop.DBus.Properties", "Get");
2354be560b09SZhu, Yunge 
2355be560b09SZhu, Yunge         method.append("xyz.openbmc_project.Configuration.LedFault",
2356be560b09SZhu, Yunge                       "LedGpioPins");
2357be560b09SZhu, Yunge 
2358be560b09SZhu, Yunge         try
2359be560b09SZhu, Yunge         {
236015419dd5SVernon Mauery             auto reply = dbus->call(method);
2361be560b09SZhu, Yunge             reply.read(message);
2362be560b09SZhu, Yunge             ledgpios = std::get<std::vector<uint64_t>>(message);
2363be560b09SZhu, Yunge         }
2364be560b09SZhu, Yunge         catch (std::exception& e)
2365be560b09SZhu, Yunge         {
2366be560b09SZhu, Yunge             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2367be560b09SZhu, Yunge             return ipmi::responseResponseError();
2368be560b09SZhu, Yunge         }
2369be560b09SZhu, Yunge 
2370be560b09SZhu, Yunge         // Check the size to be sure it will never overflow on groupSize
2371be560b09SZhu, Yunge         if (ledgpios.size() > groupSize)
2372be560b09SZhu, Yunge         {
2373be560b09SZhu, Yunge             phosphor::logging::log<phosphor::logging::level::ERR>(
2374be560b09SZhu, Yunge                 "Fault gpio Pins out of range!");
2375be560b09SZhu, Yunge             return ipmi::responseParmOutOfRange();
2376be560b09SZhu, Yunge         }
2377be560b09SZhu, Yunge         // Store data, according to command data bit index order
2378be560b09SZhu, Yunge         for (int i = 0; i < ledgpios.size(); i++)
2379be560b09SZhu, Yunge         {
2380be560b09SZhu, Yunge             ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2381be560b09SZhu, Yunge         }
2382be560b09SZhu, Yunge     }
2383be560b09SZhu, Yunge 
2384be560b09SZhu, Yunge     switch (RemoteFaultType(faultType))
2385be560b09SZhu, Yunge     {
2386be560b09SZhu, Yunge         case (RemoteFaultType::fan):
2387be560b09SZhu, Yunge         case (RemoteFaultType::memory):
2388be560b09SZhu, Yunge         {
2389be560b09SZhu, Yunge             if (faultGroup == skipLEDs)
2390be560b09SZhu, Yunge             {
2391be560b09SZhu, Yunge                 return ipmi::responseSuccess();
2392be560b09SZhu, Yunge             }
2393be560b09SZhu, Yunge 
2394be560b09SZhu, Yunge             uint64_t ledState = 0;
2395be560b09SZhu, Yunge             // calculate led state bit filed count, each byte has 8bits
2396be560b09SZhu, Yunge             // the maximum bits will be 8 * 8 bits
2397be560b09SZhu, Yunge             constexpr uint8_t size = sizeof(ledStateData) * 8;
2398be560b09SZhu, Yunge             for (int i = 0; i < sizeof(ledStateData); i++)
2399be560b09SZhu, Yunge             {
2400be560b09SZhu, Yunge                 ledState = (uint64_t)(ledState << 8);
2401be560b09SZhu, Yunge                 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2402be560b09SZhu, Yunge             }
2403be560b09SZhu, Yunge 
2404be560b09SZhu, Yunge             std::bitset<size> ledStateBits(ledState);
2405be560b09SZhu, Yunge             std::string gpioValue;
2406be560b09SZhu, Yunge             for (int i = 0; i < size; i++)
2407be560b09SZhu, Yunge             { // skip invalid value
2408be560b09SZhu, Yunge                 if (ledFaultPins[i] == 0xFFFF)
2409be560b09SZhu, Yunge                 {
2410be560b09SZhu, Yunge                     continue;
2411be560b09SZhu, Yunge                 }
2412be560b09SZhu, Yunge 
2413be560b09SZhu, Yunge                 std::string device = sysGpioPath +
2414be560b09SZhu, Yunge                                      std::to_string(ledFaultPins[i]) +
2415be560b09SZhu, Yunge                                      postfixValue;
2416be560b09SZhu, Yunge                 std::fstream gpioFile;
2417be560b09SZhu, Yunge 
2418be560b09SZhu, Yunge                 gpioFile.open(device, std::ios::out);
2419be560b09SZhu, Yunge 
2420be560b09SZhu, Yunge                 if (!gpioFile.good())
2421be560b09SZhu, Yunge                 {
2422be560b09SZhu, Yunge                     phosphor::logging::log<phosphor::logging::level::ERR>(
2423be560b09SZhu, Yunge                         "Not Find Led Gpio Device!",
2424be560b09SZhu, Yunge                         phosphor::logging::entry("DEVICE=%s", device.c_str()));
2425be560b09SZhu, Yunge                     return ipmi::responseResponseError();
2426be560b09SZhu, Yunge                 }
2427be560b09SZhu, Yunge                 gpioFile << std::to_string(
2428be560b09SZhu, Yunge                     static_cast<uint8_t>(ledStateBits[i]));
2429be560b09SZhu, Yunge                 gpioFile.close();
2430be560b09SZhu, Yunge             }
2431be560b09SZhu, Yunge             break;
2432be560b09SZhu, Yunge         }
2433be560b09SZhu, Yunge         default:
2434be560b09SZhu, Yunge         {
2435be560b09SZhu, Yunge             // now only support two fault types
2436be560b09SZhu, Yunge             return ipmi::responseParmOutOfRange();
2437be560b09SZhu, Yunge         }
2438be560b09SZhu, Yunge     }
2439be560b09SZhu, Yunge 
2440be560b09SZhu, Yunge     return ipmi::responseSuccess();
2441be560b09SZhu, Yunge }
2442be560b09SZhu, Yunge 
2443ea537d53SRichard Marian Thomaiyar ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2444ea537d53SRichard Marian Thomaiyar {
2445ea537d53SRichard Marian Thomaiyar     uint8_t prodId = 0;
2446ea537d53SRichard Marian Thomaiyar     try
2447ea537d53SRichard Marian Thomaiyar     {
244815419dd5SVernon Mauery         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2449ea537d53SRichard Marian Thomaiyar         const DbusObjectInfo& object = getDbusObject(
245015419dd5SVernon Mauery             *dbus, "xyz.openbmc_project.Inventory.Item.Board",
2451ea537d53SRichard Marian Thomaiyar             "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2452ea537d53SRichard Marian Thomaiyar         const Value& propValue = getDbusProperty(
245315419dd5SVernon Mauery             *dbus, object.second, object.first,
2454ea537d53SRichard Marian Thomaiyar             "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2455ea537d53SRichard Marian Thomaiyar         prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2456ea537d53SRichard Marian Thomaiyar     }
2457ea537d53SRichard Marian Thomaiyar     catch (std::exception& e)
2458ea537d53SRichard Marian Thomaiyar     {
2459ea537d53SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2460ea537d53SRichard Marian Thomaiyar             "ipmiOEMReadBoardProductId: Product ID read failed!",
2461ea537d53SRichard Marian Thomaiyar             phosphor::logging::entry("ERR=%s", e.what()));
2462ea537d53SRichard Marian Thomaiyar     }
2463ea537d53SRichard Marian Thomaiyar     return ipmi::responseSuccess(prodId);
2464ea537d53SRichard Marian Thomaiyar }
2465ea537d53SRichard Marian Thomaiyar 
2466d801e463SRichard Marian Thomaiyar /** @brief implements the get security mode command
2467d801e463SRichard Marian Thomaiyar  *  @param ctx - ctx pointer
2468d801e463SRichard Marian Thomaiyar  *
2469d801e463SRichard Marian Thomaiyar  *  @returns IPMI completion code with following data
2470d801e463SRichard Marian Thomaiyar  *   - restriction mode value - As specified in
2471d801e463SRichard Marian Thomaiyar  * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2472d801e463SRichard Marian Thomaiyar  *   - special mode value - As specified in
2473d801e463SRichard Marian Thomaiyar  * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2474d801e463SRichard Marian Thomaiyar  */
2475d801e463SRichard Marian Thomaiyar ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2476d801e463SRichard Marian Thomaiyar {
2477d801e463SRichard Marian Thomaiyar     namespace securityNameSpace =
2478d801e463SRichard Marian Thomaiyar         sdbusplus::xyz::openbmc_project::Control::Security::server;
2479d801e463SRichard Marian Thomaiyar     uint8_t restrictionModeValue = 0;
2480d801e463SRichard Marian Thomaiyar     uint8_t specialModeValue = 0;
2481d801e463SRichard Marian Thomaiyar 
2482d801e463SRichard Marian Thomaiyar     boost::system::error_code ec;
2483d801e463SRichard Marian Thomaiyar     auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
248428c7290cSJames Feist         ctx->yield, ec, restricionModeService, restricionModeBasePath,
2485d801e463SRichard Marian Thomaiyar         dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2486d801e463SRichard Marian Thomaiyar         restricionModeProperty);
2487d801e463SRichard Marian Thomaiyar     if (ec)
2488d801e463SRichard Marian Thomaiyar     {
2489d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2490d801e463SRichard Marian Thomaiyar             "ipmiGetSecurityMode: failed to get RestrictionMode property",
2491d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2492d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2493d801e463SRichard Marian Thomaiyar     }
2494d801e463SRichard Marian Thomaiyar     restrictionModeValue = static_cast<uint8_t>(
2495d801e463SRichard Marian Thomaiyar         securityNameSpace::RestrictionMode::convertModesFromString(
2496d801e463SRichard Marian Thomaiyar             std::get<std::string>(varRestrMode)));
2497d801e463SRichard Marian Thomaiyar     auto varSpecialMode = ctx->bus->yield_method_call<std::variant<uint8_t>>(
249828c7290cSJames Feist         ctx->yield, ec, specialModeService, specialModeBasePath,
2499d801e463SRichard Marian Thomaiyar         dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2500d801e463SRichard Marian Thomaiyar         specialModeProperty);
2501d801e463SRichard Marian Thomaiyar     if (ec)
2502d801e463SRichard Marian Thomaiyar     {
2503d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2504d801e463SRichard Marian Thomaiyar             "ipmiGetSecurityMode: failed to get SpecialMode property",
2505d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2506d801e463SRichard Marian Thomaiyar         // fall through, let us not worry about SpecialMode property, which is
2507d801e463SRichard Marian Thomaiyar         // not required in user scenario
2508d801e463SRichard Marian Thomaiyar     }
2509d801e463SRichard Marian Thomaiyar     else
2510d801e463SRichard Marian Thomaiyar     {
2511d801e463SRichard Marian Thomaiyar         specialModeValue = std::get<uint8_t>(varSpecialMode);
2512d801e463SRichard Marian Thomaiyar     }
2513d801e463SRichard Marian Thomaiyar     return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2514d801e463SRichard Marian Thomaiyar }
2515d801e463SRichard Marian Thomaiyar 
2516d801e463SRichard Marian Thomaiyar /** @brief implements the set security mode command
2517d801e463SRichard Marian Thomaiyar  *  Command allows to upgrade the restriction mode and won't allow
2518d801e463SRichard Marian Thomaiyar  *  to downgrade from system interface
2519d801e463SRichard Marian Thomaiyar  *  @param ctx - ctx pointer
2520d801e463SRichard Marian Thomaiyar  *  @param restrictionMode - restriction mode value to be set.
2521d801e463SRichard Marian Thomaiyar  *
2522d801e463SRichard Marian Thomaiyar  *  @returns IPMI completion code
2523d801e463SRichard Marian Thomaiyar  */
2524d801e463SRichard Marian Thomaiyar ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
2525d801e463SRichard Marian Thomaiyar                                     uint8_t restrictionMode)
2526d801e463SRichard Marian Thomaiyar {
2527d801e463SRichard Marian Thomaiyar     namespace securityNameSpace =
2528d801e463SRichard Marian Thomaiyar         sdbusplus::xyz::openbmc_project::Control::Security::server;
2529d801e463SRichard Marian Thomaiyar 
2530d801e463SRichard Marian Thomaiyar     ChannelInfo chInfo;
2531d801e463SRichard Marian Thomaiyar     if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2532d801e463SRichard Marian Thomaiyar     {
2533d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2534d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode: Failed to get Channel Info",
2535d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2536d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2537d801e463SRichard Marian Thomaiyar     }
2538d801e463SRichard Marian Thomaiyar     auto reqMode =
2539d801e463SRichard Marian Thomaiyar         static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2540d801e463SRichard Marian Thomaiyar 
2541d801e463SRichard Marian Thomaiyar     if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2542d801e463SRichard Marian Thomaiyar         (reqMode >
2543d801e463SRichard Marian Thomaiyar          securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2544d801e463SRichard Marian Thomaiyar     {
2545d801e463SRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
2546d801e463SRichard Marian Thomaiyar     }
2547d801e463SRichard Marian Thomaiyar 
2548d801e463SRichard Marian Thomaiyar     boost::system::error_code ec;
2549d801e463SRichard Marian Thomaiyar     auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
255028c7290cSJames Feist         ctx->yield, ec, restricionModeService, restricionModeBasePath,
2551d801e463SRichard Marian Thomaiyar         dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2552d801e463SRichard Marian Thomaiyar         restricionModeProperty);
2553d801e463SRichard Marian Thomaiyar     if (ec)
2554d801e463SRichard Marian Thomaiyar     {
2555d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2556d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode: failed to get RestrictionMode property",
2557d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2558d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2559d801e463SRichard Marian Thomaiyar     }
2560d801e463SRichard Marian Thomaiyar     auto currentRestrictionMode =
2561d801e463SRichard Marian Thomaiyar         securityNameSpace::RestrictionMode::convertModesFromString(
2562d801e463SRichard Marian Thomaiyar             std::get<std::string>(varRestrMode));
2563d801e463SRichard Marian Thomaiyar 
2564d801e463SRichard Marian Thomaiyar     if (chInfo.mediumType !=
2565d801e463SRichard Marian Thomaiyar             static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2566d801e463SRichard Marian Thomaiyar         currentRestrictionMode > reqMode)
2567d801e463SRichard Marian Thomaiyar     {
2568d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2569d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode - Downgrading security mode not supported "
2570d801e463SRichard Marian Thomaiyar             "through system interface",
2571d801e463SRichard Marian Thomaiyar             phosphor::logging::entry(
2572d801e463SRichard Marian Thomaiyar                 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2573d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2574d801e463SRichard Marian Thomaiyar         return ipmi::responseCommandNotAvailable();
2575d801e463SRichard Marian Thomaiyar     }
2576d801e463SRichard Marian Thomaiyar 
2577d801e463SRichard Marian Thomaiyar     ec.clear();
2578d801e463SRichard Marian Thomaiyar     ctx->bus->yield_method_call<>(
257928c7290cSJames Feist         ctx->yield, ec, restricionModeService, restricionModeBasePath,
2580d801e463SRichard Marian Thomaiyar         dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2581d801e463SRichard Marian Thomaiyar         restricionModeProperty,
2582d801e463SRichard Marian Thomaiyar         static_cast<std::variant<std::string>>(
2583d801e463SRichard Marian Thomaiyar             securityNameSpace::convertForMessage(reqMode)));
2584d801e463SRichard Marian Thomaiyar 
2585d801e463SRichard Marian Thomaiyar     if (ec)
2586d801e463SRichard Marian Thomaiyar     {
2587d801e463SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(
2588d801e463SRichard Marian Thomaiyar             "ipmiSetSecurityMode: failed to set RestrictionMode property",
2589d801e463SRichard Marian Thomaiyar             phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2590d801e463SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
2591d801e463SRichard Marian Thomaiyar     }
2592d801e463SRichard Marian Thomaiyar     return ipmi::responseSuccess();
2593d801e463SRichard Marian Thomaiyar }
2594d801e463SRichard Marian Thomaiyar 
25954ac799d7SVernon Mauery ipmi::RspType<uint8_t /* restore status */>
25964ac799d7SVernon Mauery     ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
25974ac799d7SVernon Mauery {
25984ac799d7SVernon Mauery     static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
25994ac799d7SVernon Mauery 
26004ac799d7SVernon Mauery     if (clr != expClr)
26014ac799d7SVernon Mauery     {
26024ac799d7SVernon Mauery         return ipmi::responseInvalidFieldRequest();
26034ac799d7SVernon Mauery     }
26044ac799d7SVernon Mauery     constexpr uint8_t cmdStatus = 0;
26054ac799d7SVernon Mauery     constexpr uint8_t cmdDefaultRestore = 0xaa;
26064ac799d7SVernon Mauery     constexpr uint8_t cmdFullRestore = 0xbb;
26074ac799d7SVernon Mauery     constexpr uint8_t cmdFormat = 0xcc;
26084ac799d7SVernon Mauery 
26094ac799d7SVernon Mauery     constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
26104ac799d7SVernon Mauery 
26114ac799d7SVernon Mauery     switch (cmd)
26124ac799d7SVernon Mauery     {
26134ac799d7SVernon Mauery         case cmdStatus:
26144ac799d7SVernon Mauery             break;
26154ac799d7SVernon Mauery         case cmdDefaultRestore:
26164ac799d7SVernon Mauery         case cmdFullRestore:
26174ac799d7SVernon Mauery         case cmdFormat:
26184ac799d7SVernon Mauery         {
26194ac799d7SVernon Mauery             // write file to rwfs root
26204ac799d7SVernon Mauery             int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
26214ac799d7SVernon Mauery             std::ofstream restoreFile(restoreOpFname);
26224ac799d7SVernon Mauery             if (!restoreFile)
26234ac799d7SVernon Mauery             {
26244ac799d7SVernon Mauery                 return ipmi::responseUnspecifiedError();
26254ac799d7SVernon Mauery             }
26264ac799d7SVernon Mauery             restoreFile << value << "\n";
26274ac799d7SVernon Mauery             break;
26284ac799d7SVernon Mauery         }
26294ac799d7SVernon Mauery         default:
26304ac799d7SVernon Mauery             return ipmi::responseInvalidFieldRequest();
26314ac799d7SVernon Mauery     }
26324ac799d7SVernon Mauery 
26334ac799d7SVernon Mauery     constexpr uint8_t restorePending = 0;
26344ac799d7SVernon Mauery     constexpr uint8_t restoreComplete = 1;
26354ac799d7SVernon Mauery 
26364ac799d7SVernon Mauery     uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
26374ac799d7SVernon Mauery                                 ? restorePending
26384ac799d7SVernon Mauery                                 : restoreComplete;
26394ac799d7SVernon Mauery     return ipmi::responseSuccess(restoreStatus);
26404ac799d7SVernon Mauery }
26414ac799d7SVernon Mauery 
264239736d59SChen Yugang ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
264339736d59SChen Yugang {
264439736d59SChen Yugang     uint8_t bmcSource;
264539736d59SChen Yugang     namespace nmi = sdbusplus::com::intel::Control::server;
264639736d59SChen Yugang 
264739736d59SChen Yugang     try
264839736d59SChen Yugang     {
264939736d59SChen Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
265039736d59SChen Yugang         std::string service =
265139736d59SChen Yugang             getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
265239736d59SChen Yugang         Value variant =
265339736d59SChen Yugang             getDbusProperty(*dbus, service, oemNmiSourceObjPath,
265439736d59SChen Yugang                             oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
265539736d59SChen Yugang 
265639736d59SChen Yugang         switch (nmi::NMISource::convertBMCSourceSignalFromString(
265739736d59SChen Yugang             std::get<std::string>(variant)))
265839736d59SChen Yugang         {
265939736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::None:
266039736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::none);
266139736d59SChen Yugang                 break;
266239736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::FpBtn:
266339736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
266439736d59SChen Yugang                 break;
266539736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
266639736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
266739736d59SChen Yugang                 break;
266839736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::PefMatch:
266939736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
267039736d59SChen Yugang                 break;
267139736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::ChassisCmd:
267239736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
267339736d59SChen Yugang                 break;
267439736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::MemoryError:
267539736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
267639736d59SChen Yugang                 break;
267739736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
267839736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
267939736d59SChen Yugang                 break;
268039736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
268139736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
268239736d59SChen Yugang                 break;
268339736d59SChen Yugang             case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
268439736d59SChen Yugang                 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
268539736d59SChen Yugang                 break;
268639736d59SChen Yugang             default:
268739736d59SChen Yugang                 phosphor::logging::log<phosphor::logging::level::ERR>(
268839736d59SChen Yugang                     "NMI source: invalid property!",
268939736d59SChen Yugang                     phosphor::logging::entry(
269039736d59SChen Yugang                         "PROP=%s", std::get<std::string>(variant).c_str()));
269139736d59SChen Yugang                 return ipmi::responseResponseError();
269239736d59SChen Yugang         }
269339736d59SChen Yugang     }
269439736d59SChen Yugang     catch (sdbusplus::exception::SdBusError& e)
269539736d59SChen Yugang     {
269639736d59SChen Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
269739736d59SChen Yugang         return ipmi::responseResponseError();
269839736d59SChen Yugang     }
269939736d59SChen Yugang 
270039736d59SChen Yugang     return ipmi::responseSuccess(bmcSource);
270139736d59SChen Yugang }
270239736d59SChen Yugang 
270339736d59SChen Yugang ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
270439736d59SChen Yugang {
270539736d59SChen Yugang     namespace nmi = sdbusplus::com::intel::Control::server;
270639736d59SChen Yugang 
270739736d59SChen Yugang     nmi::NMISource::BMCSourceSignal bmcSourceSignal =
270839736d59SChen Yugang         nmi::NMISource::BMCSourceSignal::None;
270939736d59SChen Yugang 
271039736d59SChen Yugang     switch (NmiSource(sourceId))
271139736d59SChen Yugang     {
271239736d59SChen Yugang         case NmiSource::none:
271339736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
271439736d59SChen Yugang             break;
271539736d59SChen Yugang         case NmiSource::fpBtn:
271639736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
271739736d59SChen Yugang             break;
271839736d59SChen Yugang         case NmiSource::wdPreTimeout:
271939736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
272039736d59SChen Yugang             break;
272139736d59SChen Yugang         case NmiSource::pefMatch:
272239736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
272339736d59SChen Yugang             break;
272439736d59SChen Yugang         case NmiSource::chassisCmd:
272539736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
272639736d59SChen Yugang             break;
272739736d59SChen Yugang         case NmiSource::memoryError:
272839736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
272939736d59SChen Yugang             break;
273039736d59SChen Yugang         case NmiSource::pciSerrPerr:
273139736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
273239736d59SChen Yugang             break;
273339736d59SChen Yugang         case NmiSource::southbridgeNmi:
273439736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
273539736d59SChen Yugang             break;
273639736d59SChen Yugang         case NmiSource::chipsetNmi:
273739736d59SChen Yugang             bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
273839736d59SChen Yugang             break;
273939736d59SChen Yugang         default:
274039736d59SChen Yugang             phosphor::logging::log<phosphor::logging::level::ERR>(
274139736d59SChen Yugang                 "NMI source: invalid property!");
274239736d59SChen Yugang             return ipmi::responseResponseError();
274339736d59SChen Yugang     }
274439736d59SChen Yugang 
274539736d59SChen Yugang     try
274639736d59SChen Yugang     {
274739736d59SChen Yugang         // keep NMI signal source
274839736d59SChen Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
274939736d59SChen Yugang         std::string service =
275039736d59SChen Yugang             getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
275139736d59SChen Yugang         setDbusProperty(
275239736d59SChen Yugang             *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
275339736d59SChen Yugang             oemNmiBmcSourceObjPathProp,
275439736d59SChen Yugang             sdbusplus::com::intel::Control::server::convertForMessage(
275539736d59SChen Yugang                 bmcSourceSignal));
275699be6330SChen Yugang         // set Enabled property to inform NMI source handling
275799be6330SChen Yugang         // to trigger a NMI_OUT BSOD.
275899be6330SChen Yugang         // if it's triggered by NMI source property changed,
275999be6330SChen Yugang         // NMI_OUT BSOD could be missed if the same source occurs twice in a row
276099be6330SChen Yugang         if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
276199be6330SChen Yugang         {
276299be6330SChen Yugang             setDbusProperty(*dbus, service, oemNmiSourceObjPath,
276399be6330SChen Yugang                             oemNmiSourceIntf, oemNmiEnabledObjPathProp,
276499be6330SChen Yugang                             static_cast<bool>(true));
276599be6330SChen Yugang         }
276639736d59SChen Yugang     }
276739736d59SChen Yugang     catch (sdbusplus::exception_t& e)
276839736d59SChen Yugang     {
276939736d59SChen Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
277039736d59SChen Yugang         return ipmi::responseResponseError();
277139736d59SChen Yugang     }
277239736d59SChen Yugang 
277339736d59SChen Yugang     return ipmi::responseSuccess();
277439736d59SChen Yugang }
277539736d59SChen Yugang 
277663efafacSJames Feist namespace dimmOffset
277763efafacSJames Feist {
277863efafacSJames Feist constexpr const char* dimmPower = "DimmPower";
277963efafacSJames Feist constexpr const char* staticCltt = "StaticCltt";
278063efafacSJames Feist constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
278163efafacSJames Feist constexpr const char* offsetInterface =
278263efafacSJames Feist     "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
278363efafacSJames Feist constexpr const char* property = "DimmOffset";
278463efafacSJames Feist 
278563efafacSJames Feist }; // namespace dimmOffset
278663efafacSJames Feist 
278763efafacSJames Feist ipmi::RspType<>
278863efafacSJames Feist     ipmiOEMSetDimmOffset(uint8_t type,
278963efafacSJames Feist                          const std::vector<std::tuple<uint8_t, uint8_t>>& data)
279063efafacSJames Feist {
279163efafacSJames Feist     if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
279263efafacSJames Feist         type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
279363efafacSJames Feist     {
279463efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
279563efafacSJames Feist     }
279663efafacSJames Feist 
279763efafacSJames Feist     if (data.empty())
279863efafacSJames Feist     {
279963efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
280063efafacSJames Feist     }
280163efafacSJames Feist     nlohmann::json json;
280263efafacSJames Feist 
280363efafacSJames Feist     std::ifstream jsonStream(dimmOffsetFile);
280463efafacSJames Feist     if (jsonStream.good())
280563efafacSJames Feist     {
280663efafacSJames Feist         json = nlohmann::json::parse(jsonStream, nullptr, false);
280763efafacSJames Feist         if (json.is_discarded())
280863efafacSJames Feist         {
280963efafacSJames Feist             json = nlohmann::json();
281063efafacSJames Feist         }
281163efafacSJames Feist         jsonStream.close();
281263efafacSJames Feist     }
281363efafacSJames Feist 
281463efafacSJames Feist     std::string typeName;
281563efafacSJames Feist     if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
281663efafacSJames Feist     {
281763efafacSJames Feist         typeName = dimmOffset::dimmPower;
281863efafacSJames Feist     }
281963efafacSJames Feist     else
282063efafacSJames Feist     {
282163efafacSJames Feist         typeName = dimmOffset::staticCltt;
282263efafacSJames Feist     }
282363efafacSJames Feist 
282463efafacSJames Feist     nlohmann::json& field = json[typeName];
282563efafacSJames Feist 
282663efafacSJames Feist     for (const auto& [index, value] : data)
282763efafacSJames Feist     {
282863efafacSJames Feist         field[index] = value;
282963efafacSJames Feist     }
283063efafacSJames Feist 
283163efafacSJames Feist     for (nlohmann::json& val : field)
283263efafacSJames Feist     {
283363efafacSJames Feist         if (val == nullptr)
283463efafacSJames Feist         {
283563efafacSJames Feist             val = static_cast<uint8_t>(0);
283663efafacSJames Feist         }
283763efafacSJames Feist     }
283863efafacSJames Feist 
283963efafacSJames Feist     std::ofstream output(dimmOffsetFile);
284063efafacSJames Feist     if (!output.good())
284163efafacSJames Feist     {
284263efafacSJames Feist         std::cerr << "Error writing json file\n";
284363efafacSJames Feist         return ipmi::responseResponseError();
284463efafacSJames Feist     }
284563efafacSJames Feist 
284663efafacSJames Feist     output << json.dump(4);
284763efafacSJames Feist 
284863efafacSJames Feist     if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
284963efafacSJames Feist     {
285063efafacSJames Feist         std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
285163efafacSJames Feist 
285263efafacSJames Feist         std::variant<std::vector<uint8_t>> offsets =
285363efafacSJames Feist             field.get<std::vector<uint8_t>>();
285463efafacSJames Feist         auto call = bus->new_method_call(
285563efafacSJames Feist             settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
285663efafacSJames Feist         call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
285763efafacSJames Feist         try
285863efafacSJames Feist         {
285963efafacSJames Feist             bus->call(call);
286063efafacSJames Feist         }
286163efafacSJames Feist         catch (sdbusplus::exception_t& e)
286263efafacSJames Feist         {
286363efafacSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
286463efafacSJames Feist                 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
286563efafacSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
286663efafacSJames Feist             return ipmi::responseResponseError();
286763efafacSJames Feist         }
286863efafacSJames Feist     }
286963efafacSJames Feist 
287063efafacSJames Feist     return ipmi::responseSuccess();
287163efafacSJames Feist }
287263efafacSJames Feist 
287363efafacSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
287463efafacSJames Feist {
287563efafacSJames Feist 
287663efafacSJames Feist     if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
287763efafacSJames Feist         type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
287863efafacSJames Feist     {
287963efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
288063efafacSJames Feist     }
288163efafacSJames Feist 
288263efafacSJames Feist     std::ifstream jsonStream(dimmOffsetFile);
288363efafacSJames Feist 
288463efafacSJames Feist     auto json = nlohmann::json::parse(jsonStream, nullptr, false);
288563efafacSJames Feist     if (json.is_discarded())
288663efafacSJames Feist     {
288763efafacSJames Feist         std::cerr << "File error in " << dimmOffsetFile << "\n";
288863efafacSJames Feist         return ipmi::responseResponseError();
288963efafacSJames Feist     }
289063efafacSJames Feist 
289163efafacSJames Feist     std::string typeName;
289263efafacSJames Feist     if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
289363efafacSJames Feist     {
289463efafacSJames Feist         typeName = dimmOffset::dimmPower;
289563efafacSJames Feist     }
289663efafacSJames Feist     else
289763efafacSJames Feist     {
289863efafacSJames Feist         typeName = dimmOffset::staticCltt;
289963efafacSJames Feist     }
290063efafacSJames Feist 
290163efafacSJames Feist     auto it = json.find(typeName);
290263efafacSJames Feist     if (it == json.end())
290363efafacSJames Feist     {
290463efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
290563efafacSJames Feist     }
290663efafacSJames Feist 
290763efafacSJames Feist     if (it->size() <= index)
290863efafacSJames Feist     {
290963efafacSJames Feist         return ipmi::responseInvalidFieldRequest();
291063efafacSJames Feist     }
291163efafacSJames Feist 
291263efafacSJames Feist     uint8_t resp = it->at(index).get<uint8_t>();
291363efafacSJames Feist     return ipmi::responseSuccess(resp);
291463efafacSJames Feist }
291563efafacSJames Feist 
29164f7e76bbSChen,Yugang namespace boot_options
29174f7e76bbSChen,Yugang {
29184f7e76bbSChen,Yugang 
29194f7e76bbSChen,Yugang using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
29204f7e76bbSChen,Yugang using IpmiValue = uint8_t;
29214f7e76bbSChen,Yugang constexpr auto ipmiDefault = 0;
29224f7e76bbSChen,Yugang 
29234f7e76bbSChen,Yugang std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
29244f7e76bbSChen,Yugang     {0x01, Source::Sources::Network},
29254f7e76bbSChen,Yugang     {0x02, Source::Sources::Disk},
29264f7e76bbSChen,Yugang     {0x05, Source::Sources::ExternalMedia},
29274f7e76bbSChen,Yugang     {0x0f, Source::Sources::RemovableMedia},
29284f7e76bbSChen,Yugang     {ipmiDefault, Source::Sources::Default}};
29294f7e76bbSChen,Yugang 
29304f7e76bbSChen,Yugang std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
2931ca12a7beSChen Yugang     {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
29324f7e76bbSChen,Yugang 
29334f7e76bbSChen,Yugang std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
29344f7e76bbSChen,Yugang     {Source::Sources::Network, 0x01},
29354f7e76bbSChen,Yugang     {Source::Sources::Disk, 0x02},
29364f7e76bbSChen,Yugang     {Source::Sources::ExternalMedia, 0x05},
29374f7e76bbSChen,Yugang     {Source::Sources::RemovableMedia, 0x0f},
29384f7e76bbSChen,Yugang     {Source::Sources::Default, ipmiDefault}};
29394f7e76bbSChen,Yugang 
29404f7e76bbSChen,Yugang std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
2941ca12a7beSChen Yugang     {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
29424f7e76bbSChen,Yugang 
29434f7e76bbSChen,Yugang static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
29444f7e76bbSChen,Yugang static constexpr auto bootSourceIntf =
29454f7e76bbSChen,Yugang     "xyz.openbmc_project.Control.Boot.Source";
29464f7e76bbSChen,Yugang static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
29474f7e76bbSChen,Yugang static constexpr auto persistentObjPath =
29484f7e76bbSChen,Yugang     "/xyz/openbmc_project/control/host0/boot";
29494f7e76bbSChen,Yugang static constexpr auto oneTimePath =
29504f7e76bbSChen,Yugang     "/xyz/openbmc_project/control/host0/boot/one_time";
29514f7e76bbSChen,Yugang static constexpr auto bootSourceProp = "BootSource";
29524f7e76bbSChen,Yugang static constexpr auto bootModeProp = "BootMode";
29534f7e76bbSChen,Yugang static constexpr auto oneTimeBootEnableProp = "Enabled";
29544f7e76bbSChen,Yugang static constexpr auto httpBootMode =
29554f7e76bbSChen,Yugang     "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
29564f7e76bbSChen,Yugang 
29574f7e76bbSChen,Yugang enum class BootOptionParameter : size_t
29584f7e76bbSChen,Yugang {
29594f7e76bbSChen,Yugang     setInProgress = 0x0,
29604f7e76bbSChen,Yugang     bootFlags = 0x5,
29614f7e76bbSChen,Yugang };
29624f7e76bbSChen,Yugang static constexpr uint8_t setComplete = 0x0;
29634f7e76bbSChen,Yugang static constexpr uint8_t setInProgress = 0x1;
29644f7e76bbSChen,Yugang static uint8_t transferStatus = setComplete;
29654f7e76bbSChen,Yugang static constexpr uint8_t setParmVersion = 0x01;
29664f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
29674f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
29684f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
29694f7e76bbSChen,Yugang static constexpr uint8_t httpBoot = 0xd;
29704f7e76bbSChen,Yugang static constexpr uint8_t bootSourceMask = 0x3c;
29714f7e76bbSChen,Yugang 
29724f7e76bbSChen,Yugang } // namespace boot_options
29734f7e76bbSChen,Yugang 
29744f7e76bbSChen,Yugang ipmi::RspType<uint8_t,               // version
29754f7e76bbSChen,Yugang               uint8_t,               // param
29764f7e76bbSChen,Yugang               uint8_t,               // data0, dependent on parameter
29774f7e76bbSChen,Yugang               std::optional<uint8_t> // data1, dependent on parameter
29784f7e76bbSChen,Yugang               >
29794f7e76bbSChen,Yugang     ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
29804f7e76bbSChen,Yugang {
29814f7e76bbSChen,Yugang     using namespace boot_options;
29824f7e76bbSChen,Yugang     uint8_t bootOption = 0;
29834f7e76bbSChen,Yugang 
29844f7e76bbSChen,Yugang     if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
29854f7e76bbSChen,Yugang     {
29864f7e76bbSChen,Yugang         return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
29874f7e76bbSChen,Yugang                                      std::nullopt);
29884f7e76bbSChen,Yugang     }
29894f7e76bbSChen,Yugang 
29904f7e76bbSChen,Yugang     if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
29914f7e76bbSChen,Yugang     {
29924f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(
29934f7e76bbSChen,Yugang             "Unsupported parameter");
29944f7e76bbSChen,Yugang         return ipmi::responseResponseError();
29954f7e76bbSChen,Yugang     }
29964f7e76bbSChen,Yugang 
29974f7e76bbSChen,Yugang     try
29984f7e76bbSChen,Yugang     {
29994f7e76bbSChen,Yugang         auto oneTimeEnabled = false;
30004f7e76bbSChen,Yugang         // read one time Enabled property
30014f7e76bbSChen,Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
30024f7e76bbSChen,Yugang         std::string service = getService(*dbus, enabledIntf, oneTimePath);
30034f7e76bbSChen,Yugang         Value variant = getDbusProperty(*dbus, service, oneTimePath,
30044f7e76bbSChen,Yugang                                         enabledIntf, oneTimeBootEnableProp);
30054f7e76bbSChen,Yugang         oneTimeEnabled = std::get<bool>(variant);
30064f7e76bbSChen,Yugang 
30074f7e76bbSChen,Yugang         // get BootSource and BootMode properties
30084f7e76bbSChen,Yugang         // according to oneTimeEnable
30094f7e76bbSChen,Yugang         auto bootObjPath = oneTimePath;
30104f7e76bbSChen,Yugang         if (oneTimeEnabled == false)
30114f7e76bbSChen,Yugang         {
30124f7e76bbSChen,Yugang             bootObjPath = persistentObjPath;
30134f7e76bbSChen,Yugang         }
30144f7e76bbSChen,Yugang 
30154f7e76bbSChen,Yugang         service = getService(*dbus, bootModeIntf, bootObjPath);
30164f7e76bbSChen,Yugang         variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
30174f7e76bbSChen,Yugang                                   bootModeProp);
30184f7e76bbSChen,Yugang 
30194f7e76bbSChen,Yugang         auto bootMode =
30204f7e76bbSChen,Yugang             Mode::convertModesFromString(std::get<std::string>(variant));
30214f7e76bbSChen,Yugang 
30224f7e76bbSChen,Yugang         service = getService(*dbus, bootSourceIntf, bootObjPath);
30234f7e76bbSChen,Yugang         variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
30244f7e76bbSChen,Yugang                                   bootSourceProp);
30254f7e76bbSChen,Yugang 
30264f7e76bbSChen,Yugang         if (std::get<std::string>(variant) == httpBootMode)
30274f7e76bbSChen,Yugang         {
30284f7e76bbSChen,Yugang             bootOption = httpBoot;
30294f7e76bbSChen,Yugang         }
30304f7e76bbSChen,Yugang         else
30314f7e76bbSChen,Yugang         {
30324f7e76bbSChen,Yugang             auto bootSource = Source::convertSourcesFromString(
30334f7e76bbSChen,Yugang                 std::get<std::string>(variant));
30344f7e76bbSChen,Yugang             bootOption = sourceDbusToIpmi.at(bootSource);
30354f7e76bbSChen,Yugang             if (Source::Sources::Default == bootSource)
30364f7e76bbSChen,Yugang             {
30374f7e76bbSChen,Yugang                 bootOption = modeDbusToIpmi.at(bootMode);
30384f7e76bbSChen,Yugang             }
30394f7e76bbSChen,Yugang         }
30404f7e76bbSChen,Yugang 
30414f7e76bbSChen,Yugang         uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
30424f7e76bbSChen,Yugang                                          : setParmBootFlagsValidPermanent;
30434f7e76bbSChen,Yugang         bootOption <<= 2; // shift for responseconstexpr
30444f7e76bbSChen,Yugang         return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
30454f7e76bbSChen,Yugang                                      bootOption);
30464f7e76bbSChen,Yugang     }
30474f7e76bbSChen,Yugang     catch (sdbusplus::exception_t& e)
30484f7e76bbSChen,Yugang     {
30494f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
30504f7e76bbSChen,Yugang         return ipmi::responseResponseError();
30514f7e76bbSChen,Yugang     }
30524f7e76bbSChen,Yugang }
30534f7e76bbSChen,Yugang 
30544f7e76bbSChen,Yugang ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
30554f7e76bbSChen,Yugang                                          std::optional<uint8_t> bootOption)
30564f7e76bbSChen,Yugang {
30574f7e76bbSChen,Yugang     using namespace boot_options;
30584f7e76bbSChen,Yugang     auto oneTimeEnabled = false;
30594f7e76bbSChen,Yugang 
30604f7e76bbSChen,Yugang     if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
30614f7e76bbSChen,Yugang     {
30624f7e76bbSChen,Yugang         if (bootOption)
30634f7e76bbSChen,Yugang         {
30644f7e76bbSChen,Yugang             return ipmi::responseReqDataLenInvalid();
30654f7e76bbSChen,Yugang         }
30664f7e76bbSChen,Yugang 
30674f7e76bbSChen,Yugang         if (transferStatus == setInProgress)
30684f7e76bbSChen,Yugang         {
30694f7e76bbSChen,Yugang             phosphor::logging::log<phosphor::logging::level::ERR>(
30704f7e76bbSChen,Yugang                 "boot option set in progress!");
30714f7e76bbSChen,Yugang             return ipmi::responseResponseError();
30724f7e76bbSChen,Yugang         }
30734f7e76bbSChen,Yugang 
30744f7e76bbSChen,Yugang         transferStatus = bootParam;
30754f7e76bbSChen,Yugang         return ipmi::responseSuccess();
30764f7e76bbSChen,Yugang     }
30774f7e76bbSChen,Yugang 
30784f7e76bbSChen,Yugang     if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
30794f7e76bbSChen,Yugang     {
30804f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(
30814f7e76bbSChen,Yugang             "Unsupported parameter");
30824f7e76bbSChen,Yugang         return ipmi::responseResponseError();
30834f7e76bbSChen,Yugang     }
30844f7e76bbSChen,Yugang 
30854f7e76bbSChen,Yugang     if (!bootOption)
30864f7e76bbSChen,Yugang     {
30874f7e76bbSChen,Yugang         return ipmi::responseReqDataLenInvalid();
30884f7e76bbSChen,Yugang     }
30894f7e76bbSChen,Yugang 
30904f7e76bbSChen,Yugang     if (((bootOption.value() & bootSourceMask) >> 2) !=
30914f7e76bbSChen,Yugang         httpBoot) // not http boot, exit
30924f7e76bbSChen,Yugang     {
30934f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(
30944f7e76bbSChen,Yugang             "wrong boot option parameter!");
30954f7e76bbSChen,Yugang         return ipmi::responseParmOutOfRange();
30964f7e76bbSChen,Yugang     }
30974f7e76bbSChen,Yugang 
30984f7e76bbSChen,Yugang     try
30994f7e76bbSChen,Yugang     {
31004f7e76bbSChen,Yugang         bool permanent = (bootParam & setParmBootFlagsPermanent) ==
31014f7e76bbSChen,Yugang                          setParmBootFlagsPermanent;
31024f7e76bbSChen,Yugang 
31034f7e76bbSChen,Yugang         // read one time Enabled property
31044f7e76bbSChen,Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
31054f7e76bbSChen,Yugang         std::string service = getService(*dbus, enabledIntf, oneTimePath);
31064f7e76bbSChen,Yugang         Value variant = getDbusProperty(*dbus, service, oneTimePath,
31074f7e76bbSChen,Yugang                                         enabledIntf, oneTimeBootEnableProp);
31084f7e76bbSChen,Yugang         oneTimeEnabled = std::get<bool>(variant);
31094f7e76bbSChen,Yugang 
31104f7e76bbSChen,Yugang         /*
31114f7e76bbSChen,Yugang          * Check if the current boot setting is onetime or permanent, if the
31124f7e76bbSChen,Yugang          * request in the command is otherwise, then set the "Enabled"
31134f7e76bbSChen,Yugang          * property in one_time object path to 'True' to indicate onetime
31144f7e76bbSChen,Yugang          * and 'False' to indicate permanent.
31154f7e76bbSChen,Yugang          *
31164f7e76bbSChen,Yugang          * Once the onetime/permanent setting is applied, then the bootMode
31174f7e76bbSChen,Yugang          * and bootSource is updated for the corresponding object.
31184f7e76bbSChen,Yugang          */
31194f7e76bbSChen,Yugang         if (permanent == oneTimeEnabled)
31204f7e76bbSChen,Yugang         {
31214f7e76bbSChen,Yugang             setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
31224f7e76bbSChen,Yugang                             oneTimeBootEnableProp, !permanent);
31234f7e76bbSChen,Yugang         }
31244f7e76bbSChen,Yugang 
31254f7e76bbSChen,Yugang         // set BootSource and BootMode properties
31264f7e76bbSChen,Yugang         // according to oneTimeEnable or persistent
31274f7e76bbSChen,Yugang         auto bootObjPath = oneTimePath;
31284f7e76bbSChen,Yugang         if (oneTimeEnabled == false)
31294f7e76bbSChen,Yugang         {
31304f7e76bbSChen,Yugang             bootObjPath = persistentObjPath;
31314f7e76bbSChen,Yugang         }
31324f7e76bbSChen,Yugang         std::string bootMode =
31334f7e76bbSChen,Yugang             "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
31344f7e76bbSChen,Yugang         std::string bootSource = httpBootMode;
31354f7e76bbSChen,Yugang 
31364f7e76bbSChen,Yugang         service = getService(*dbus, bootModeIntf, bootObjPath);
31374f7e76bbSChen,Yugang         setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
31384f7e76bbSChen,Yugang                         bootMode);
31394f7e76bbSChen,Yugang 
31404f7e76bbSChen,Yugang         service = getService(*dbus, bootSourceIntf, bootObjPath);
31414f7e76bbSChen,Yugang         setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
31424f7e76bbSChen,Yugang                         bootSourceProp, bootSource);
31434f7e76bbSChen,Yugang     }
31444f7e76bbSChen,Yugang     catch (sdbusplus::exception_t& e)
31454f7e76bbSChen,Yugang     {
31464f7e76bbSChen,Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
31474f7e76bbSChen,Yugang         return ipmi::responseResponseError();
31484f7e76bbSChen,Yugang     }
31494f7e76bbSChen,Yugang 
31504f7e76bbSChen,Yugang     return ipmi::responseSuccess();
31514f7e76bbSChen,Yugang }
31524f7e76bbSChen,Yugang 
3153ca12a7beSChen Yugang ipmi::RspType<> ipmiOemSetBootOptions(uint8_t bootFlag, uint8_t bootParam,
3154ca12a7beSChen Yugang                                       std::optional<uint8_t> bootOption)
3155ca12a7beSChen Yugang {
3156ca12a7beSChen Yugang     bool oneTimeEnabled = false;
3157ca12a7beSChen Yugang     uint8_t bootOptionValue = 0;
3158ca12a7beSChen Yugang     static constexpr const uint8_t shiftBits = 2;
3159ca12a7beSChen Yugang 
3160ca12a7beSChen Yugang     if (bootFlag ==
3161ca12a7beSChen Yugang         static_cast<uint8_t>(boot_options::BootOptionParameter::setInProgress))
3162ca12a7beSChen Yugang     {
3163ca12a7beSChen Yugang         if (bootOption)
3164ca12a7beSChen Yugang         {
3165ca12a7beSChen Yugang             return ipmi::responseReqDataLenInvalid();
3166ca12a7beSChen Yugang         }
3167ca12a7beSChen Yugang 
3168ca12a7beSChen Yugang         if (boot_options::transferStatus == boot_options::setInProgress)
3169ca12a7beSChen Yugang         {
3170ca12a7beSChen Yugang             phosphor::logging::log<phosphor::logging::level::ERR>(
3171ca12a7beSChen Yugang                 "boot option set in progress!");
3172ca12a7beSChen Yugang             return ipmi::responseResponseError();
3173ca12a7beSChen Yugang         }
3174ca12a7beSChen Yugang 
3175ca12a7beSChen Yugang         boot_options::transferStatus = bootParam;
3176ca12a7beSChen Yugang         return ipmi::responseSuccess();
3177ca12a7beSChen Yugang     }
3178ca12a7beSChen Yugang 
3179ca12a7beSChen Yugang     if (bootFlag !=
3180ca12a7beSChen Yugang         static_cast<uint8_t>(boot_options::BootOptionParameter::bootFlags))
3181ca12a7beSChen Yugang     {
3182ca12a7beSChen Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(
3183ca12a7beSChen Yugang             "Unsupported parameter");
3184ca12a7beSChen Yugang         return ipmi::responseResponseError();
3185ca12a7beSChen Yugang     }
3186ca12a7beSChen Yugang 
3187ca12a7beSChen Yugang     if (!bootOption)
3188ca12a7beSChen Yugang     {
3189ca12a7beSChen Yugang         return ipmi::responseReqDataLenInvalid();
3190ca12a7beSChen Yugang     }
3191ca12a7beSChen Yugang     bootOptionValue =
3192ca12a7beSChen Yugang         (bootOption.value() & boot_options::bootSourceMask) >> shiftBits;
3193ca12a7beSChen Yugang 
3194ca12a7beSChen Yugang     try
3195ca12a7beSChen Yugang     {
3196ca12a7beSChen Yugang         bool permanent =
3197ca12a7beSChen Yugang             (bootParam & boot_options::setParmBootFlagsPermanent) ==
3198ca12a7beSChen Yugang             boot_options::setParmBootFlagsPermanent;
3199ca12a7beSChen Yugang         auto bootMode = boot_options::Mode::Modes::Regular;
3200ca12a7beSChen Yugang         auto bootSource = boot_options::Source::Sources::Default;
3201ca12a7beSChen Yugang 
3202ca12a7beSChen Yugang         // read one time Enabled property
3203ca12a7beSChen Yugang         std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3204ca12a7beSChen Yugang         std::string service = getService(*dbus, boot_options::enabledIntf,
3205ca12a7beSChen Yugang                                          boot_options::oneTimePath);
3206ca12a7beSChen Yugang         Value variant = getDbusProperty(
3207ca12a7beSChen Yugang             *dbus, service, boot_options::oneTimePath,
3208ca12a7beSChen Yugang             boot_options::enabledIntf, boot_options::oneTimeBootEnableProp);
3209ca12a7beSChen Yugang         oneTimeEnabled = std::get_if<bool>(&variant);
3210ca12a7beSChen Yugang 
3211ca12a7beSChen Yugang         /*
3212ca12a7beSChen Yugang          * Check if the current boot setting is onetime or permanent, if the
3213ca12a7beSChen Yugang          * request in the command is otherwise, then set the "Enabled"
3214ca12a7beSChen Yugang          * property in one_time object path to 'True' to indicate onetime
3215ca12a7beSChen Yugang          * and 'False' to indicate permanent.
3216ca12a7beSChen Yugang          *
3217ca12a7beSChen Yugang          * Once the onetime/permanent setting is applied, then the bootMode
3218ca12a7beSChen Yugang          * and bootSource is updated for the corresponding object.
3219ca12a7beSChen Yugang          */
3220ca12a7beSChen Yugang         if (permanent == oneTimeEnabled)
3221ca12a7beSChen Yugang         {
3222ca12a7beSChen Yugang             setDbusProperty(*dbus, service, boot_options::oneTimePath,
3223ca12a7beSChen Yugang                             boot_options::enabledIntf,
3224ca12a7beSChen Yugang                             boot_options::oneTimeBootEnableProp, !permanent);
3225ca12a7beSChen Yugang         }
3226ca12a7beSChen Yugang 
3227ca12a7beSChen Yugang         // set BootSource and BootMode properties
3228ca12a7beSChen Yugang         // according to oneTimeEnable or persistent
3229ca12a7beSChen Yugang         auto bootObjPath = boot_options::oneTimePath;
3230ca12a7beSChen Yugang         if (oneTimeEnabled == false)
3231ca12a7beSChen Yugang         {
3232ca12a7beSChen Yugang             bootObjPath = boot_options::persistentObjPath;
3233ca12a7beSChen Yugang         }
3234ca12a7beSChen Yugang 
3235ca12a7beSChen Yugang         auto modeItr = boot_options::modeIpmiToDbus.find(bootOptionValue);
3236ca12a7beSChen Yugang         auto sourceItr = boot_options::sourceIpmiToDbus.find(bootOptionValue);
3237ca12a7beSChen Yugang 
3238ca12a7beSChen Yugang         if (boot_options::sourceIpmiToDbus.end() != sourceItr)
3239ca12a7beSChen Yugang         {
3240ca12a7beSChen Yugang             bootSource = sourceItr->second;
3241ca12a7beSChen Yugang         }
3242ca12a7beSChen Yugang 
3243ca12a7beSChen Yugang         if (boot_options::modeIpmiToDbus.end() != modeItr)
3244ca12a7beSChen Yugang         {
3245ca12a7beSChen Yugang             bootMode = modeItr->second;
3246ca12a7beSChen Yugang         }
3247ca12a7beSChen Yugang 
3248ca12a7beSChen Yugang         if ((boot_options::modeIpmiToDbus.end() == modeItr) &&
3249ca12a7beSChen Yugang             (boot_options::sourceIpmiToDbus.end() == sourceItr))
3250ca12a7beSChen Yugang         {
3251ca12a7beSChen Yugang             // return error if boot option is not supported
3252ca12a7beSChen Yugang             return ipmi::responseInvalidFieldRequest();
3253ca12a7beSChen Yugang         }
3254ca12a7beSChen Yugang         service = getService(*dbus, boot_options::bootModeIntf, bootObjPath);
3255ca12a7beSChen Yugang         setDbusProperty(*dbus, service, bootObjPath, boot_options::bootModeIntf,
3256ca12a7beSChen Yugang                         boot_options::bootModeProp,
3257ca12a7beSChen Yugang                         convertForMessage(bootMode));
3258ca12a7beSChen Yugang 
3259ca12a7beSChen Yugang         service = getService(*dbus, boot_options::bootSourceIntf, bootObjPath);
3260ca12a7beSChen Yugang         setDbusProperty(
3261ca12a7beSChen Yugang             *dbus, service, bootObjPath, boot_options::bootSourceIntf,
3262ca12a7beSChen Yugang             boot_options::bootSourceProp, convertForMessage(bootSource));
3263ca12a7beSChen Yugang     }
3264ca12a7beSChen Yugang     catch (sdbusplus::exception_t& e)
3265ca12a7beSChen Yugang     {
3266ca12a7beSChen Yugang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3267ca12a7beSChen Yugang         return ipmi::responseResponseError();
3268ca12a7beSChen Yugang     }
3269ca12a7beSChen Yugang 
3270ca12a7beSChen Yugang     return ipmi::responseSuccess();
3271ca12a7beSChen Yugang }
3272ca12a7beSChen Yugang 
327364796041SJason M. Bills static void registerOEMFunctions(void)
3274a835eaa0SJia, Chunhui {
3275a835eaa0SJia, Chunhui     phosphor::logging::log<phosphor::logging::level::INFO>(
3276a835eaa0SJia, Chunhui         "Registering OEM commands");
327798bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
3278a835eaa0SJia, Chunhui                          ipmiOEMWildcard,
3279a835eaa0SJia, Chunhui                          PRIVILEGE_USER); // wildcard default handler
328098bbf69aSVernon Mauery 
328198bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
328264796041SJason M. Bills                          ipmiOEMWildcard,
328364796041SJason M. Bills                          PRIVILEGE_USER); // wildcard default handler
328498bbf69aSVernon Mauery 
328598bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
328698bbf69aSVernon Mauery                          intel::general::cmdGetChassisIdentifier, NULL,
328798bbf69aSVernon Mauery                          ipmiOEMGetChassisIdentifier,
3288a835eaa0SJia, Chunhui                          PRIVILEGE_USER); // get chassis identifier
328998bbf69aSVernon Mauery 
329098bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
329164796041SJason M. Bills                          NULL, ipmiOEMSetSystemGUID,
3292a835eaa0SJia, Chunhui                          PRIVILEGE_ADMIN); // set system guid
3293b02bf095SJason M. Bills 
3294b02bf095SJason M. Bills     // <Disable BMC System Reset Action>
329598bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
329698bbf69aSVernon Mauery                     intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
329798bbf69aSVernon Mauery                     ipmiOEMDisableBMCSystemReset);
329898bbf69aSVernon Mauery 
3299b02bf095SJason M. Bills     // <Get BMC Reset Disables>
330098bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
330198bbf69aSVernon Mauery                     intel::general::cmdGetBMCResetDisables, Privilege::Admin,
330298bbf69aSVernon Mauery                     ipmiOEMGetBMCResetDisables);
3303b02bf095SJason M. Bills 
330498bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
330564796041SJason M. Bills                          NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
3306cc49b54bSJia, Chunhui 
330798bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
330898bbf69aSVernon Mauery                          intel::general::cmdGetOEMDeviceInfo, NULL,
330998bbf69aSVernon Mauery                          ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
3310cc49b54bSJia, Chunhui 
331198bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
331298bbf69aSVernon Mauery                          intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
331398bbf69aSVernon Mauery                          ipmiOEMGetAICFRU, PRIVILEGE_USER);
3314d509eb91SSuryakanth Sekar 
331598bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
331698bbf69aSVernon Mauery                     intel::general::cmdSendEmbeddedFWUpdStatus,
331798bbf69aSVernon Mauery                     Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
3318d509eb91SSuryakanth Sekar 
331998bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
332098bbf69aSVernon Mauery                          intel::general::cmdSetPowerRestoreDelay, NULL,
332198bbf69aSVernon Mauery                          ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
332298bbf69aSVernon Mauery 
332398bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
332498bbf69aSVernon Mauery                          intel::general::cmdGetPowerRestoreDelay, NULL,
332598bbf69aSVernon Mauery                          ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
332698bbf69aSVernon Mauery 
332798bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
332898bbf69aSVernon Mauery                     intel::general::cmdSetOEMUser2Activation,
332998bbf69aSVernon Mauery                     Privilege::Callback, ipmiOEMSetUser2Activation);
333098bbf69aSVernon Mauery 
333198bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
333298bbf69aSVernon Mauery                     intel::general::cmdSetSpecialUserPassword,
333398bbf69aSVernon Mauery                     Privilege::Callback, ipmiOEMSetSpecialUserPassword);
3334fc5e985bSRichard Marian Thomaiyar 
333542bd9c8eSJason M. Bills     // <Get Processor Error Config>
333698bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
333798bbf69aSVernon Mauery                     intel::general::cmdGetProcessorErrConfig, Privilege::User,
333898bbf69aSVernon Mauery                     ipmiOEMGetProcessorErrConfig);
333998bbf69aSVernon Mauery 
334042bd9c8eSJason M. Bills     // <Set Processor Error Config>
334198bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
334298bbf69aSVernon Mauery                     intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
334398bbf69aSVernon Mauery                     ipmiOEMSetProcessorErrConfig);
334442bd9c8eSJason M. Bills 
334598bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
334698bbf69aSVernon Mauery                          intel::general::cmdSetShutdownPolicy, NULL,
334798bbf69aSVernon Mauery                          ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
334891244a6aSJames Feist 
334998bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral,
335098bbf69aSVernon Mauery                          intel::general::cmdGetShutdownPolicy, NULL,
335198bbf69aSVernon Mauery                          ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
335298bbf69aSVernon Mauery 
335398bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetFanConfig,
335491244a6aSJames Feist                          NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
335591244a6aSJames Feist 
335698bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
335798bbf69aSVernon Mauery                     intel::general::cmdGetFanConfig, Privilege::User,
335898bbf69aSVernon Mauery                     ipmiOEMGetFanConfig);
335991244a6aSJames Feist 
336098bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
336198bbf69aSVernon Mauery                     intel::general::cmdGetFanSpeedOffset, Privilege::User,
336298bbf69aSVernon Mauery                     ipmiOEMGetFanSpeedOffset);
33635f957cafSJames Feist 
336498bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
336598bbf69aSVernon Mauery                     intel::general::cmdSetFanSpeedOffset, Privilege::User,
336698bbf69aSVernon Mauery                     ipmiOEMSetFanSpeedOffset);
3367acc8a4ebSJames Feist 
336898bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
336998bbf69aSVernon Mauery                     intel::general::cmdSetFscParameter, Privilege::User,
337098bbf69aSVernon Mauery                     ipmiOEMSetFscParameter);
3371acc8a4ebSJames Feist 
337298bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
337398bbf69aSVernon Mauery                     intel::general::cmdGetFscParameter, Privilege::User,
337498bbf69aSVernon Mauery                     ipmiOEMGetFscParameter);
33755f957cafSJames Feist 
337698bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
337798bbf69aSVernon Mauery                     intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
337898bbf69aSVernon Mauery                     ipmiOEMReadBoardProductId);
3379ea537d53SRichard Marian Thomaiyar 
338098bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
338198bbf69aSVernon Mauery                     intel::general::cmdGetNmiStatus, Privilege::User,
338298bbf69aSVernon Mauery                     ipmiOEMGetNmiSource);
338339736d59SChen Yugang 
338498bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
338598bbf69aSVernon Mauery                     intel::general::cmdSetNmiStatus, Privilege::Operator,
338698bbf69aSVernon Mauery                     ipmiOEMSetNmiSource);
338739736d59SChen Yugang 
338898bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
338998bbf69aSVernon Mauery                     intel::general::cmdGetEfiBootOptions, Privilege::User,
339098bbf69aSVernon Mauery                     ipmiOemGetEfiBootOptions);
33914f7e76bbSChen,Yugang 
339298bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
339398bbf69aSVernon Mauery                     intel::general::cmdSetEfiBootOptions, Privilege::Operator,
339498bbf69aSVernon Mauery                     ipmiOemSetEfiBootOptions);
33954f7e76bbSChen,Yugang 
339698bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
339798bbf69aSVernon Mauery                     intel::general::cmdGetSecurityMode, Privilege::User,
339898bbf69aSVernon Mauery                     ipmiGetSecurityMode);
3399d801e463SRichard Marian Thomaiyar 
340098bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
340198bbf69aSVernon Mauery                     intel::general::cmdSetSecurityMode, Privilege::Admin,
340298bbf69aSVernon Mauery                     ipmiSetSecurityMode);
3403d801e463SRichard Marian Thomaiyar 
340498bbf69aSVernon Mauery     ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
340545f04988SKuiying Wang                          NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
34064ac799d7SVernon Mauery 
340798bbf69aSVernon Mauery     ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
340898bbf69aSVernon Mauery                          ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
340998bbf69aSVernon Mauery                          ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3410773703a5SCheng C Yang 
341198bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
341298bbf69aSVernon Mauery                     intel::general::cmdSetFaultIndication, Privilege::Operator,
341398bbf69aSVernon Mauery                     ipmiOEMSetFaultIndication);
341498bbf69aSVernon Mauery 
341598bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
341698bbf69aSVernon Mauery                     intel::general::cmdSetColdRedundancyConfig, Privilege::User,
341798bbf69aSVernon Mauery                     ipmiOEMSetCRConfig);
341898bbf69aSVernon Mauery 
341998bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
342098bbf69aSVernon Mauery                     intel::general::cmdGetColdRedundancyConfig, Privilege::User,
342198bbf69aSVernon Mauery                     ipmiOEMGetCRConfig);
342298bbf69aSVernon Mauery 
342398bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
342498bbf69aSVernon Mauery                     intel::general::cmdRestoreConfiguration, Privilege::Admin,
34254ac799d7SVernon Mauery                     ipmiRestoreConfiguration);
342663efafacSJames Feist 
342798bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
342898bbf69aSVernon Mauery                     intel::general::cmdSetDimmOffset, Privilege::Operator,
342998bbf69aSVernon Mauery                     ipmiOEMSetDimmOffset);
343063efafacSJames Feist 
343198bbf69aSVernon Mauery     registerHandler(prioOemBase, intel::netFnGeneral,
343298bbf69aSVernon Mauery                     intel::general::cmdGetDimmOffset, Privilege::Operator,
343398bbf69aSVernon Mauery                     ipmiOEMGetDimmOffset);
3434ca12a7beSChen Yugang 
343598bbf69aSVernon Mauery     registerHandler(prioOemBase, netFnChassis, chassis::cmdSetSystemBootOptions,
343698bbf69aSVernon Mauery                     Privilege::Operator, ipmiOemSetBootOptions);
3437a835eaa0SJia, Chunhui }
3438a835eaa0SJia, Chunhui 
3439a835eaa0SJia, Chunhui } // namespace ipmi
3440