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>
2664796041SJason M. Bills #include <commandutils.hpp>
27a835eaa0SJia, Chunhui #include <iostream>
28cc49b54bSJia, Chunhui #include <ipmid/api.hpp>
295480ef62SVernon Mauery #include <ipmid/utils.hpp>
30a835eaa0SJia, Chunhui #include <oemcommands.hpp>
31a835eaa0SJia, Chunhui #include <phosphor-logging/log.hpp>
32a835eaa0SJia, Chunhui #include <sdbusplus/bus.hpp>
33d509eb91SSuryakanth Sekar #include <sdbusplus/message/types.hpp>
34a835eaa0SJia, Chunhui #include <string>
3591244a6aSJames Feist #include <variant>
36a835eaa0SJia, Chunhui #include <vector>
37a835eaa0SJia, Chunhui 
38a835eaa0SJia, Chunhui namespace ipmi
39a835eaa0SJia, Chunhui {
4064796041SJason M. Bills static void registerOEMFunctions() __attribute__((constructor));
416d9c83fdSJason M. Bills sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
4264796041SJason M. Bills static constexpr size_t maxFRUStringLength = 0x3F;
43a835eaa0SJia, Chunhui 
44d509eb91SSuryakanth Sekar static constexpr auto ethernetIntf =
45d509eb91SSuryakanth Sekar     "xyz.openbmc_project.Network.EthernetInterface";
46d509eb91SSuryakanth Sekar static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
47d509eb91SSuryakanth Sekar static constexpr auto networkService = "xyz.openbmc_project.Network";
48d509eb91SSuryakanth Sekar static constexpr auto networkRoot = "/xyz/openbmc_project/network";
49d509eb91SSuryakanth Sekar 
50a835eaa0SJia, Chunhui // return code: 0 successful
51a835eaa0SJia, Chunhui int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
52a835eaa0SJia, Chunhui {
53a835eaa0SJia, Chunhui     std::string objpath = "/xyz/openbmc_project/FruDevice";
54a835eaa0SJia, Chunhui     std::string intf = "xyz.openbmc_project.FruDeviceManager";
55a835eaa0SJia, Chunhui     std::string service = getService(bus, intf, objpath);
56a835eaa0SJia, Chunhui     ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
57a835eaa0SJia, Chunhui     if (valueTree.empty())
58a835eaa0SJia, Chunhui     {
59a835eaa0SJia, Chunhui         phosphor::logging::log<phosphor::logging::level::ERR>(
60a835eaa0SJia, Chunhui             "No object implements interface",
61a835eaa0SJia, Chunhui             phosphor::logging::entry("INTF=%s", intf.c_str()));
62a835eaa0SJia, Chunhui         return -1;
63a835eaa0SJia, Chunhui     }
64a835eaa0SJia, Chunhui 
6564796041SJason M. Bills     for (const auto& item : valueTree)
66a835eaa0SJia, Chunhui     {
67a835eaa0SJia, Chunhui         auto interface = item.second.find("xyz.openbmc_project.FruDevice");
68a835eaa0SJia, Chunhui         if (interface == item.second.end())
69a835eaa0SJia, Chunhui         {
70a835eaa0SJia, Chunhui             continue;
71a835eaa0SJia, Chunhui         }
72a835eaa0SJia, Chunhui 
73a835eaa0SJia, Chunhui         auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
74a835eaa0SJia, Chunhui         if (property == interface->second.end())
75a835eaa0SJia, Chunhui         {
76a835eaa0SJia, Chunhui             continue;
77a835eaa0SJia, Chunhui         }
78a835eaa0SJia, Chunhui 
79a835eaa0SJia, Chunhui         try
80a835eaa0SJia, Chunhui         {
81a835eaa0SJia, Chunhui             Value variant = property->second;
8264796041SJason M. Bills             std::string& result =
8364796041SJason M. Bills                 sdbusplus::message::variant_ns::get<std::string>(variant);
8464796041SJason M. Bills             if (result.size() > maxFRUStringLength)
85a835eaa0SJia, Chunhui             {
86a835eaa0SJia, Chunhui                 phosphor::logging::log<phosphor::logging::level::ERR>(
87a835eaa0SJia, Chunhui                     "FRU serial number exceed maximum length");
88a835eaa0SJia, Chunhui                 return -1;
89a835eaa0SJia, Chunhui             }
90a835eaa0SJia, Chunhui             serial = result;
91a835eaa0SJia, Chunhui             return 0;
92a835eaa0SJia, Chunhui         }
9364796041SJason M. Bills         catch (sdbusplus::message::variant_ns::bad_variant_access& e)
94a835eaa0SJia, Chunhui         {
9564796041SJason M. Bills             phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
96a835eaa0SJia, Chunhui             return -1;
97a835eaa0SJia, Chunhui         }
98a835eaa0SJia, Chunhui     }
99a835eaa0SJia, Chunhui     return -1;
100a835eaa0SJia, Chunhui }
10164796041SJason M. Bills 
102a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
103a835eaa0SJia, Chunhui                            ipmi_request_t request, ipmi_response_t response,
10464796041SJason M. Bills                            ipmi_data_len_t dataLen, ipmi_context_t context)
105a835eaa0SJia, Chunhui {
10664796041SJason M. Bills     printCommand(+netfn, +cmd);
107a835eaa0SJia, Chunhui     // Status code.
108a835eaa0SJia, Chunhui     ipmi_ret_t rc = IPMI_CC_INVALID;
10964796041SJason M. Bills     *dataLen = 0;
110a835eaa0SJia, Chunhui     return rc;
111a835eaa0SJia, Chunhui }
112a835eaa0SJia, Chunhui 
113a835eaa0SJia, Chunhui // Returns the Chassis Identifier (serial #)
114a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
115a835eaa0SJia, Chunhui                                        ipmi_request_t request,
116a835eaa0SJia, Chunhui                                        ipmi_response_t response,
11764796041SJason M. Bills                                        ipmi_data_len_t dataLen,
118a835eaa0SJia, Chunhui                                        ipmi_context_t context)
119a835eaa0SJia, Chunhui {
120a835eaa0SJia, Chunhui     std::string serial;
12164796041SJason M. Bills     if (*dataLen != 0) // invalid request if there are extra parameters
122a835eaa0SJia, Chunhui     {
12364796041SJason M. Bills         *dataLen = 0;
124a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
125a835eaa0SJia, Chunhui     }
12664796041SJason M. Bills     if (getChassisSerialNumber(dbus, serial) == 0)
127a835eaa0SJia, Chunhui     {
12864796041SJason M. Bills         *dataLen = serial.size(); // length will never exceed response length
129a835eaa0SJia, Chunhui                                   // as it is checked in getChassisSerialNumber
130a835eaa0SJia, Chunhui         char* resp = static_cast<char*>(response);
13164796041SJason M. Bills         serial.copy(resp, *dataLen);
132a835eaa0SJia, Chunhui         return IPMI_CC_OK;
133a835eaa0SJia, Chunhui     }
13464796041SJason M. Bills     *dataLen = 0;
135a835eaa0SJia, Chunhui     return IPMI_CC_RESPONSE_ERROR;
136a835eaa0SJia, Chunhui }
137a835eaa0SJia, Chunhui 
138a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
139a835eaa0SJia, Chunhui                                 ipmi_request_t request,
140a835eaa0SJia, Chunhui                                 ipmi_response_t response,
14164796041SJason M. Bills                                 ipmi_data_len_t dataLen, ipmi_context_t context)
142a835eaa0SJia, Chunhui {
143a835eaa0SJia, Chunhui     static constexpr size_t safeBufferLength = 50;
144a835eaa0SJia, Chunhui     char buf[safeBufferLength] = {0};
145a835eaa0SJia, Chunhui     GUIDData* Data = reinterpret_cast<GUIDData*>(request);
146a835eaa0SJia, Chunhui 
14764796041SJason M. Bills     if (*dataLen != sizeof(GUIDData)) // 16bytes
148a835eaa0SJia, Chunhui     {
14964796041SJason M. Bills         *dataLen = 0;
150a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
151a835eaa0SJia, Chunhui     }
152a835eaa0SJia, Chunhui 
15364796041SJason M. Bills     *dataLen = 0;
154a835eaa0SJia, Chunhui 
155a835eaa0SJia, Chunhui     snprintf(
156a835eaa0SJia, Chunhui         buf, safeBufferLength,
157a835eaa0SJia, Chunhui         "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
158a835eaa0SJia, Chunhui         Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
159a835eaa0SJia, Chunhui         Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
160a835eaa0SJia, Chunhui         Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
161a835eaa0SJia, Chunhui         Data->node3, Data->node2, Data->node1);
162a835eaa0SJia, Chunhui     // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
163a835eaa0SJia, Chunhui     std::string guid = buf;
164a835eaa0SJia, Chunhui 
165a835eaa0SJia, Chunhui     std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
166a835eaa0SJia, Chunhui     std::string intf = "xyz.openbmc_project.Common.UUID";
16764796041SJason M. Bills     std::string service = getService(dbus, intf, objpath);
16864796041SJason M. Bills     setDbusProperty(dbus, service, objpath, intf, "UUID", guid);
169a835eaa0SJia, Chunhui     return IPMI_CC_OK;
170a835eaa0SJia, Chunhui }
171a835eaa0SJia, Chunhui 
172a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
173a835eaa0SJia, Chunhui                             ipmi_request_t request, ipmi_response_t response,
174a835eaa0SJia, Chunhui                             ipmi_data_len_t dataLen, ipmi_context_t context)
175a835eaa0SJia, Chunhui {
176a835eaa0SJia, Chunhui     DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
177a835eaa0SJia, Chunhui 
17864796041SJason M. Bills     if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
179a835eaa0SJia, Chunhui     {
180a835eaa0SJia, Chunhui         *dataLen = 0;
181a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
182a835eaa0SJia, Chunhui     }
18364796041SJason M. Bills     std::string idString((char*)data->biosId, data->biosIDLength);
184a835eaa0SJia, Chunhui 
18564796041SJason M. Bills     std::string service = getService(dbus, biosIntf, biosObjPath);
18664796041SJason M. Bills     setDbusProperty(dbus, service, biosObjPath, biosIntf, biosProp, idString);
187a835eaa0SJia, Chunhui     uint8_t* bytesWritten = static_cast<uint8_t*>(response);
188a835eaa0SJia, Chunhui     *bytesWritten =
18964796041SJason M. Bills         data->biosIDLength; // how many bytes are written into storage
190a835eaa0SJia, Chunhui     *dataLen = 1;
191a835eaa0SJia, Chunhui     return IPMI_CC_OK;
192a835eaa0SJia, Chunhui }
193a835eaa0SJia, Chunhui 
194a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195a835eaa0SJia, Chunhui                                 ipmi_request_t request,
196a835eaa0SJia, Chunhui                                 ipmi_response_t response,
197a835eaa0SJia, Chunhui                                 ipmi_data_len_t dataLen, ipmi_context_t context)
198a835eaa0SJia, Chunhui {
199a835eaa0SJia, Chunhui     GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
200a835eaa0SJia, Chunhui     GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
201a835eaa0SJia, Chunhui 
202a835eaa0SJia, Chunhui     if (*dataLen == 0)
203a835eaa0SJia, Chunhui     {
20464796041SJason M. Bills         *dataLen = 0;
205a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
206a835eaa0SJia, Chunhui     }
207a835eaa0SJia, Chunhui 
208a835eaa0SJia, Chunhui     size_t reqDataLen = *dataLen;
209a835eaa0SJia, Chunhui     *dataLen = 0;
21064796041SJason M. Bills     if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
211a835eaa0SJia, Chunhui     {
212a835eaa0SJia, Chunhui         return IPMI_CC_INVALID_FIELD_REQUEST;
213a835eaa0SJia, Chunhui     }
214a835eaa0SJia, Chunhui 
215a835eaa0SJia, Chunhui     // handle OEM command items
21664796041SJason M. Bills     switch (OEMDevEntityType(req->entityType))
217a835eaa0SJia, Chunhui     {
218a835eaa0SJia, Chunhui         case OEMDevEntityType::biosId:
219a835eaa0SJia, Chunhui         {
220a835eaa0SJia, Chunhui             if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
221a835eaa0SJia, Chunhui             {
222a835eaa0SJia, Chunhui                 return IPMI_CC_REQ_DATA_LEN_INVALID;
223a835eaa0SJia, Chunhui             }
224a835eaa0SJia, Chunhui 
22564796041SJason M. Bills             std::string service = getService(dbus, biosIntf, biosObjPath);
226a835eaa0SJia, Chunhui             try
227a835eaa0SJia, Chunhui             {
22864796041SJason M. Bills                 Value variant = getDbusProperty(dbus, service, biosObjPath,
229a835eaa0SJia, Chunhui                                                 biosIntf, biosProp);
23064796041SJason M. Bills                 std::string& idString =
23164796041SJason M. Bills                     sdbusplus::message::variant_ns::get<std::string>(variant);
232a835eaa0SJia, Chunhui                 if (req->offset >= idString.size())
233a835eaa0SJia, Chunhui                 {
234a835eaa0SJia, Chunhui                     return IPMI_CC_PARM_OUT_OF_RANGE;
235a835eaa0SJia, Chunhui                 }
236a835eaa0SJia, Chunhui                 size_t length = 0;
237a835eaa0SJia, Chunhui                 if (req->countToRead > (idString.size() - req->offset))
238a835eaa0SJia, Chunhui                 {
239a835eaa0SJia, Chunhui                     length = idString.size() - req->offset;
240a835eaa0SJia, Chunhui                 }
241a835eaa0SJia, Chunhui                 else
242a835eaa0SJia, Chunhui                 {
243a835eaa0SJia, Chunhui                     length = req->countToRead;
244a835eaa0SJia, Chunhui                 }
245a835eaa0SJia, Chunhui                 std::copy(idString.begin() + req->offset, idString.end(),
246a835eaa0SJia, Chunhui                           res->data);
247a835eaa0SJia, Chunhui                 res->resDatalen = length;
248a835eaa0SJia, Chunhui                 *dataLen = res->resDatalen + 1;
249a835eaa0SJia, Chunhui             }
25064796041SJason M. Bills             catch (sdbusplus::message::variant_ns::bad_variant_access& e)
251a835eaa0SJia, Chunhui             {
25264796041SJason M. Bills                 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
253a835eaa0SJia, Chunhui                 return IPMI_CC_UNSPECIFIED_ERROR;
254a835eaa0SJia, Chunhui             }
255a835eaa0SJia, Chunhui         }
256a835eaa0SJia, Chunhui         break;
257a835eaa0SJia, Chunhui 
258a835eaa0SJia, Chunhui         case OEMDevEntityType::devVer:
259a835eaa0SJia, Chunhui         case OEMDevEntityType::sdrVer:
260a835eaa0SJia, Chunhui             // TODO:
261a835eaa0SJia, Chunhui             return IPMI_CC_ILLEGAL_COMMAND;
262a835eaa0SJia, Chunhui         default:
263a835eaa0SJia, Chunhui             return IPMI_CC_INVALID_FIELD_REQUEST;
264a835eaa0SJia, Chunhui     }
265a835eaa0SJia, Chunhui     return IPMI_CC_OK;
266a835eaa0SJia, Chunhui }
267a835eaa0SJia, Chunhui 
268a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
269a835eaa0SJia, Chunhui                             ipmi_request_t request, ipmi_response_t response,
270a835eaa0SJia, Chunhui                             ipmi_data_len_t dataLen, ipmi_context_t context)
271a835eaa0SJia, Chunhui {
272a835eaa0SJia, Chunhui     if (*dataLen != 0)
273a835eaa0SJia, Chunhui     {
27464796041SJason M. Bills         *dataLen = 0;
275a835eaa0SJia, Chunhui         return IPMI_CC_REQ_DATA_LEN_INVALID;
276a835eaa0SJia, Chunhui     }
277a835eaa0SJia, Chunhui 
278a835eaa0SJia, Chunhui     *dataLen = 1;
279a835eaa0SJia, Chunhui     uint8_t* res = reinterpret_cast<uint8_t*>(response);
280a835eaa0SJia, Chunhui     // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
281a835eaa0SJia, Chunhui     // AIC is available so that BIOS will not timeout repeatly which leads to
282a835eaa0SJia, Chunhui     // slow booting.
283a835eaa0SJia, Chunhui     *res = 0; // Byte1=Count of SlotPosition/FruID records.
284a835eaa0SJia, Chunhui     return IPMI_CC_OK;
285a835eaa0SJia, Chunhui }
286a835eaa0SJia, Chunhui 
28764796041SJason M. Bills ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
28864796041SJason M. Bills                                        ipmi_request_t request,
28964796041SJason M. Bills                                        ipmi_response_t response,
29064796041SJason M. Bills                                        ipmi_data_len_t dataLen,
29164796041SJason M. Bills                                        ipmi_context_t context)
292a835eaa0SJia, Chunhui {
29364796041SJason M. Bills     GetPowerRestoreDelayRes* resp =
29464796041SJason M. Bills         reinterpret_cast<GetPowerRestoreDelayRes*>(response);
29564796041SJason M. Bills 
29664796041SJason M. Bills     if (*dataLen != 0)
29764796041SJason M. Bills     {
29864796041SJason M. Bills         *dataLen = 0;
29964796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
300a835eaa0SJia, Chunhui     }
301a835eaa0SJia, Chunhui 
30264796041SJason M. Bills     std::string service =
30364796041SJason M. Bills         getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
30464796041SJason M. Bills     Value variant =
30564796041SJason M. Bills         getDbusProperty(dbus, service, powerRestoreDelayObjPath,
30664796041SJason M. Bills                         powerRestoreDelayIntf, powerRestoreDelayProp);
30764796041SJason M. Bills 
30864796041SJason M. Bills     uint16_t delay = sdbusplus::message::variant_ns::get<uint16_t>(variant);
30964796041SJason M. Bills     resp->byteLSB = delay;
31064796041SJason M. Bills     resp->byteMSB = delay >> 8;
31164796041SJason M. Bills 
31264796041SJason M. Bills     *dataLen = sizeof(GetPowerRestoreDelayRes);
31364796041SJason M. Bills 
31464796041SJason M. Bills     return IPMI_CC_OK;
31564796041SJason M. Bills }
31664796041SJason M. Bills 
317cc49b54bSJia, Chunhui static uint8_t bcdToDec(uint8_t val)
318cc49b54bSJia, Chunhui {
319cc49b54bSJia, Chunhui     return ((val / 16 * 10) + (val % 16));
320cc49b54bSJia, Chunhui }
321cc49b54bSJia, Chunhui 
322cc49b54bSJia, Chunhui // Allows an update utility or system BIOS to send the status of an embedded
323cc49b54bSJia, Chunhui // firmware update attempt to the BMC. After received, BMC will create a logging
324cc49b54bSJia, Chunhui // record.
325cc49b54bSJia, Chunhui ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
326cc49b54bSJia, Chunhui                                                uint8_t majorRevision,
327cc49b54bSJia, Chunhui                                                uint8_t minorRevision,
328cc49b54bSJia, Chunhui                                                uint32_t auxInfo)
329cc49b54bSJia, Chunhui {
330cc49b54bSJia, Chunhui     std::string firmware;
331cc49b54bSJia, Chunhui     target = (target & selEvtTargetMask) >> selEvtTargetShift;
332cc49b54bSJia, Chunhui 
333cc49b54bSJia, Chunhui     /* make sure the status is 0, 1, or 2 as per the spec */
334cc49b54bSJia, Chunhui     if (status > 2)
335cc49b54bSJia, Chunhui     {
336cc49b54bSJia, Chunhui         return ipmi::response(ipmi::ccInvalidFieldRequest);
337cc49b54bSJia, Chunhui     }
338cc49b54bSJia, Chunhui     /*orignal OEM command is to record OEM SEL.
339cc49b54bSJia, Chunhui     But openbmc does not support OEM SEL, so we redirect it to redfish event
340cc49b54bSJia, Chunhui     logging. */
341cc49b54bSJia, Chunhui     std::string buildInfo;
342cc49b54bSJia, Chunhui     std::string action;
343cc49b54bSJia, Chunhui     switch (FWUpdateTarget(target))
344cc49b54bSJia, Chunhui     {
345cc49b54bSJia, Chunhui         case FWUpdateTarget::targetBMC:
346cc49b54bSJia, Chunhui             firmware = "BMC";
347cc49b54bSJia, Chunhui             buildInfo = " major: " + std::to_string(majorRevision) +
348cc49b54bSJia, Chunhui                         " minor: " +
349cc49b54bSJia, Chunhui                         std::to_string(bcdToDec(minorRevision)) + // BCD encoded
350cc49b54bSJia, Chunhui                         " BuildID: " + std::to_string(auxInfo);
351cc49b54bSJia, Chunhui             buildInfo += std::to_string(auxInfo);
352cc49b54bSJia, Chunhui             break;
353cc49b54bSJia, Chunhui         case FWUpdateTarget::targetBIOS:
354cc49b54bSJia, Chunhui             firmware = "BIOS";
355cc49b54bSJia, Chunhui             buildInfo =
356cc49b54bSJia, Chunhui                 " major: " +
357cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
358cc49b54bSJia, Chunhui                 " minor: " +
359cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
360cc49b54bSJia, Chunhui                 " ReleaseNumber: " +                      // ASCII encoded
361cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
362cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
363cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
364cc49b54bSJia, Chunhui                 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
365cc49b54bSJia, Chunhui             break;
366cc49b54bSJia, Chunhui         case FWUpdateTarget::targetME:
367cc49b54bSJia, Chunhui             firmware = "ME";
368cc49b54bSJia, Chunhui             buildInfo =
369cc49b54bSJia, Chunhui                 " major: " + std::to_string(majorRevision) + " minor1: " +
370cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
371cc49b54bSJia, Chunhui                 " minor2: " +
372cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
373cc49b54bSJia, Chunhui                 " build1: " +
374cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
375cc49b54bSJia, Chunhui                 " build2: " +
376cc49b54bSJia, Chunhui                 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
377cc49b54bSJia, Chunhui             break;
378cc49b54bSJia, Chunhui         case FWUpdateTarget::targetOEMEWS:
379cc49b54bSJia, Chunhui             firmware = "EWS";
380cc49b54bSJia, Chunhui             buildInfo = " major: " + std::to_string(majorRevision) +
381cc49b54bSJia, Chunhui                         " minor: " +
382cc49b54bSJia, Chunhui                         std::to_string(bcdToDec(minorRevision)) + // BCD encoded
383cc49b54bSJia, Chunhui                         " BuildID: " + std::to_string(auxInfo);
384cc49b54bSJia, Chunhui             break;
385cc49b54bSJia, Chunhui     }
386cc49b54bSJia, Chunhui 
387cc49b54bSJia, Chunhui     switch (status)
388cc49b54bSJia, Chunhui     {
389cc49b54bSJia, Chunhui         case 0x0:
390cc49b54bSJia, Chunhui             action = "update started";
391cc49b54bSJia, Chunhui             break;
392cc49b54bSJia, Chunhui         case 0x1:
393cc49b54bSJia, Chunhui             action = "update completed successfully";
394cc49b54bSJia, Chunhui             break;
395cc49b54bSJia, Chunhui         case 0x2:
396cc49b54bSJia, Chunhui             action = "update failure";
397cc49b54bSJia, Chunhui             break;
398cc49b54bSJia, Chunhui         default:
399cc49b54bSJia, Chunhui             action = "unknown";
400cc49b54bSJia, Chunhui             break;
401cc49b54bSJia, Chunhui     }
402cc49b54bSJia, Chunhui 
403cc49b54bSJia, Chunhui     std::string message(
404cc49b54bSJia, Chunhui         "[firmware update] " + firmware + " instance: " +
405cc49b54bSJia, Chunhui         std::to_string((target & targetInstanceMask) >> targetInstanceShift) +
406cc49b54bSJia, Chunhui         " status: <" + action + ">" + buildInfo);
407cc49b54bSJia, Chunhui     static constexpr const char* redfishMsgId = "FirmwareUpdate";
408cc49b54bSJia, Chunhui 
409cc49b54bSJia, Chunhui     sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
410cc49b54bSJia, Chunhui                     "REDFISH_MESSAGE_ID=%s", redfishMsgId, NULL);
411cc49b54bSJia, Chunhui     return ipmi::responseSuccess();
412cc49b54bSJia, Chunhui }
413cc49b54bSJia, Chunhui 
41464796041SJason M. Bills ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
41564796041SJason M. Bills                                        ipmi_request_t request,
41664796041SJason M. Bills                                        ipmi_response_t response,
41764796041SJason M. Bills                                        ipmi_data_len_t dataLen,
41864796041SJason M. Bills                                        ipmi_context_t context)
41964796041SJason M. Bills {
42064796041SJason M. Bills     SetPowerRestoreDelayReq* data =
42164796041SJason M. Bills         reinterpret_cast<SetPowerRestoreDelayReq*>(request);
42264796041SJason M. Bills     uint16_t delay = 0;
42364796041SJason M. Bills 
42464796041SJason M. Bills     if (*dataLen != sizeof(SetPowerRestoreDelayReq))
42564796041SJason M. Bills     {
42664796041SJason M. Bills         *dataLen = 0;
42764796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
42864796041SJason M. Bills     }
42964796041SJason M. Bills     delay = data->byteMSB;
43064796041SJason M. Bills     delay = (delay << 8) | data->byteLSB;
43164796041SJason M. Bills     std::string service =
43264796041SJason M. Bills         getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
43364796041SJason M. Bills     setDbusProperty(dbus, service, powerRestoreDelayObjPath,
43464796041SJason M. Bills                     powerRestoreDelayIntf, powerRestoreDelayProp, delay);
43564796041SJason M. Bills     *dataLen = 0;
43664796041SJason M. Bills 
43764796041SJason M. Bills     return IPMI_CC_OK;
43864796041SJason M. Bills }
43964796041SJason M. Bills 
44064796041SJason M. Bills ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
44164796041SJason M. Bills                                         ipmi_request_t request,
44264796041SJason M. Bills                                         ipmi_response_t response,
44364796041SJason M. Bills                                         ipmi_data_len_t dataLen,
44464796041SJason M. Bills                                         ipmi_context_t context)
44564796041SJason M. Bills {
44664796041SJason M. Bills     GetProcessorErrConfigRes* resp =
44764796041SJason M. Bills         reinterpret_cast<GetProcessorErrConfigRes*>(response);
44864796041SJason M. Bills 
44964796041SJason M. Bills     if (*dataLen != 0)
45064796041SJason M. Bills     {
45164796041SJason M. Bills         *dataLen = 0;
45264796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
45364796041SJason M. Bills     }
45464796041SJason M. Bills 
45564796041SJason M. Bills     std::string service =
45664796041SJason M. Bills         getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
45764796041SJason M. Bills     Value variant = getDbusProperty(dbus, service, processorErrConfigObjPath,
45864796041SJason M. Bills                                     processorErrConfigIntf, "ResetCfg");
45964796041SJason M. Bills     resp->resetCfg = sdbusplus::message::variant_ns::get<uint8_t>(variant);
46064796041SJason M. Bills 
46164796041SJason M. Bills     std::vector<uint8_t> caterrStatus;
462bc546679SKuiying Wang     sdbusplus::message::variant<std::vector<uint8_t>> message;
46364796041SJason M. Bills 
46464796041SJason M. Bills     auto method =
46564796041SJason M. Bills         dbus.new_method_call(service.c_str(), processorErrConfigObjPath,
46664796041SJason M. Bills                              "org.freedesktop.DBus.Properties", "Get");
46764796041SJason M. Bills 
46864796041SJason M. Bills     method.append(processorErrConfigIntf, "CATERRStatus");
469bc546679SKuiying Wang     auto reply = dbus.call(method);
47064796041SJason M. Bills 
47164796041SJason M. Bills     try
47264796041SJason M. Bills     {
473bc546679SKuiying Wang         reply.read(message);
474bc546679SKuiying Wang         caterrStatus =
475bc546679SKuiying Wang             sdbusplus::message::variant_ns::get<std::vector<uint8_t>>(message);
47664796041SJason M. Bills     }
47764796041SJason M. Bills     catch (sdbusplus::exception_t&)
47864796041SJason M. Bills     {
479bc546679SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(
48064796041SJason M. Bills             "ipmiOEMGetProcessorErrConfig: error on dbus",
48164796041SJason M. Bills             phosphor::logging::entry("PRORPERTY=CATERRStatus"),
48264796041SJason M. Bills             phosphor::logging::entry("PATH=%s", processorErrConfigObjPath),
48364796041SJason M. Bills             phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf));
48464796041SJason M. Bills         return IPMI_CC_UNSPECIFIED_ERROR;
48564796041SJason M. Bills     }
48664796041SJason M. Bills 
48764796041SJason M. Bills     size_t len =
48864796041SJason M. Bills         maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size();
48964796041SJason M. Bills     caterrStatus.resize(len);
49064796041SJason M. Bills     std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus);
49164796041SJason M. Bills     *dataLen = sizeof(GetProcessorErrConfigRes);
49264796041SJason M. Bills 
49364796041SJason M. Bills     return IPMI_CC_OK;
49464796041SJason M. Bills }
49564796041SJason M. Bills 
49664796041SJason M. Bills ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
49764796041SJason M. Bills                                         ipmi_request_t request,
49864796041SJason M. Bills                                         ipmi_response_t response,
49964796041SJason M. Bills                                         ipmi_data_len_t dataLen,
50064796041SJason M. Bills                                         ipmi_context_t context)
50164796041SJason M. Bills {
50264796041SJason M. Bills     SetProcessorErrConfigReq* req =
50364796041SJason M. Bills         reinterpret_cast<SetProcessorErrConfigReq*>(request);
50464796041SJason M. Bills 
50564796041SJason M. Bills     if (*dataLen != sizeof(SetProcessorErrConfigReq))
50664796041SJason M. Bills     {
50764796041SJason M. Bills         *dataLen = 0;
50864796041SJason M. Bills         return IPMI_CC_REQ_DATA_LEN_INVALID;
50964796041SJason M. Bills     }
51064796041SJason M. Bills     std::string service =
51164796041SJason M. Bills         getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
51264796041SJason M. Bills     setDbusProperty(dbus, service, processorErrConfigObjPath,
51364796041SJason M. Bills                     processorErrConfigIntf, "ResetCfg", req->resetCfg);
51464796041SJason M. Bills 
51564796041SJason M. Bills     setDbusProperty(dbus, service, processorErrConfigObjPath,
51664796041SJason M. Bills                     processorErrConfigIntf, "ResetErrorOccurrenceCounts",
51764796041SJason M. Bills                     req->resetErrorOccurrenceCounts);
51864796041SJason M. Bills     *dataLen = 0;
51964796041SJason M. Bills 
52064796041SJason M. Bills     return IPMI_CC_OK;
52164796041SJason M. Bills }
52264796041SJason M. Bills 
523703922d0SYong Li ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
524703922d0SYong Li                                     ipmi_request_t request,
525703922d0SYong Li                                     ipmi_response_t response,
526703922d0SYong Li                                     ipmi_data_len_t dataLen,
527703922d0SYong Li                                     ipmi_context_t context)
528703922d0SYong Li {
529703922d0SYong Li     GetOEMShutdownPolicyRes* resp =
530703922d0SYong Li         reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
531703922d0SYong Li 
532703922d0SYong Li     if (*dataLen != 0)
533703922d0SYong Li     {
534703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
53545f04988SKuiying Wang             "oem_get_shutdown_policy: invalid input len!");
536703922d0SYong Li         *dataLen = 0;
537703922d0SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
538703922d0SYong Li     }
539703922d0SYong Li 
540703922d0SYong Li     *dataLen = 0;
541703922d0SYong Li 
542703922d0SYong Li     try
543703922d0SYong Li     {
544703922d0SYong Li         std::string service =
545703922d0SYong Li             getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
546703922d0SYong Li         Value variant = getDbusProperty(dbus, service, oemShutdownPolicyObjPath,
547703922d0SYong Li                                         oemShutdownPolicyIntf,
548703922d0SYong Li                                         oemShutdownPolicyObjPathProp);
549703922d0SYong Li         resp->policy = sdbusplus::message::variant_ns::get<uint8_t>(variant);
550703922d0SYong Li         // TODO needs to check if it is multi-node products,
551703922d0SYong Li         // policy is only supported on node 3/4
552703922d0SYong Li         resp->policySupport = shutdownPolicySupported;
553703922d0SYong Li     }
554703922d0SYong Li     catch (sdbusplus::exception_t& e)
555703922d0SYong Li     {
556703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
557703922d0SYong Li         return IPMI_CC_UNSPECIFIED_ERROR;
558703922d0SYong Li     }
559703922d0SYong Li 
560703922d0SYong Li     *dataLen = sizeof(GetOEMShutdownPolicyRes);
561703922d0SYong Li     return IPMI_CC_OK;
562703922d0SYong Li }
563703922d0SYong Li 
564703922d0SYong Li ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
565703922d0SYong Li                                     ipmi_request_t request,
566703922d0SYong Li                                     ipmi_response_t response,
567703922d0SYong Li                                     ipmi_data_len_t dataLen,
568703922d0SYong Li                                     ipmi_context_t context)
569703922d0SYong Li {
570703922d0SYong Li     uint8_t* req = reinterpret_cast<uint8_t*>(request);
571703922d0SYong Li 
572703922d0SYong Li     // TODO needs to check if it is multi-node products,
573703922d0SYong Li     // policy is only supported on node 3/4
574703922d0SYong Li     if (*dataLen != 1)
575703922d0SYong Li     {
576703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
577703922d0SYong Li             "oem_set_shutdown_policy: invalid input len!");
578703922d0SYong Li         *dataLen = 0;
579703922d0SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
580703922d0SYong Li     }
581703922d0SYong Li 
582703922d0SYong Li     *dataLen = 0;
583703922d0SYong Li     if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
584703922d0SYong Li     {
585703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
586703922d0SYong Li             "oem_set_shutdown_policy: invalid input!");
587703922d0SYong Li         return IPMI_CC_INVALID_FIELD_REQUEST;
588703922d0SYong Li     }
589703922d0SYong Li 
590703922d0SYong Li     try
591703922d0SYong Li     {
592703922d0SYong Li         std::string service =
593703922d0SYong Li             getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
594703922d0SYong Li         setDbusProperty(dbus, service, oemShutdownPolicyObjPath,
595703922d0SYong Li                         oemShutdownPolicyIntf, oemShutdownPolicyObjPathProp,
596703922d0SYong Li                         *req);
597703922d0SYong Li     }
598703922d0SYong Li     catch (sdbusplus::exception_t& e)
599703922d0SYong Li     {
600703922d0SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
601703922d0SYong Li         return IPMI_CC_UNSPECIFIED_ERROR;
602703922d0SYong Li     }
603703922d0SYong Li 
604703922d0SYong Li     return IPMI_CC_OK;
605703922d0SYong Li }
606703922d0SYong Li 
607d509eb91SSuryakanth Sekar /** @brief implementation for check the DHCP or not in IPv4
608d509eb91SSuryakanth Sekar  *  @param[in] Channel - Channel number
609d509eb91SSuryakanth Sekar  *  @returns true or false.
610d509eb91SSuryakanth Sekar  */
611d509eb91SSuryakanth Sekar static bool isDHCPEnabled(uint8_t Channel)
612d509eb91SSuryakanth Sekar {
613d509eb91SSuryakanth Sekar     try
614d509eb91SSuryakanth Sekar     {
615d509eb91SSuryakanth Sekar         auto ethdevice = getChannelName(Channel);
616d509eb91SSuryakanth Sekar         if (ethdevice.empty())
617d509eb91SSuryakanth Sekar         {
618d509eb91SSuryakanth Sekar             return false;
619d509eb91SSuryakanth Sekar         }
620d509eb91SSuryakanth Sekar         auto ethIP = ethdevice + "/ipv4";
621d509eb91SSuryakanth Sekar         auto ethernetObj =
622d509eb91SSuryakanth Sekar             getDbusObject(dbus, networkIPIntf, networkRoot, ethIP);
623d509eb91SSuryakanth Sekar         auto value = getDbusProperty(dbus, networkService, ethernetObj.first,
624d509eb91SSuryakanth Sekar                                      networkIPIntf, "Origin");
625d509eb91SSuryakanth Sekar         if (sdbusplus::message::variant_ns::get<std::string>(value) ==
626d509eb91SSuryakanth Sekar             "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
627d509eb91SSuryakanth Sekar         {
628d509eb91SSuryakanth Sekar             return true;
629d509eb91SSuryakanth Sekar         }
630d509eb91SSuryakanth Sekar         else
631d509eb91SSuryakanth Sekar         {
632d509eb91SSuryakanth Sekar             return false;
633d509eb91SSuryakanth Sekar         }
634d509eb91SSuryakanth Sekar     }
635d509eb91SSuryakanth Sekar     catch (sdbusplus::exception_t& e)
636d509eb91SSuryakanth Sekar     {
637d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
638d509eb91SSuryakanth Sekar         return true;
639d509eb91SSuryakanth Sekar     }
640d509eb91SSuryakanth Sekar }
641d509eb91SSuryakanth Sekar 
642d509eb91SSuryakanth Sekar /** @brief implementes for check the DHCP or not in IPv6
643d509eb91SSuryakanth Sekar  *  @param[in] Channel - Channel number
644d509eb91SSuryakanth Sekar  *  @returns true or false.
645d509eb91SSuryakanth Sekar  */
646d509eb91SSuryakanth Sekar static bool isDHCPIPv6Enabled(uint8_t Channel)
647d509eb91SSuryakanth Sekar {
648d509eb91SSuryakanth Sekar 
649d509eb91SSuryakanth Sekar     try
650d509eb91SSuryakanth Sekar     {
651d509eb91SSuryakanth Sekar         auto ethdevice = getChannelName(Channel);
652d509eb91SSuryakanth Sekar         if (ethdevice.empty())
653d509eb91SSuryakanth Sekar         {
654d509eb91SSuryakanth Sekar             return false;
655d509eb91SSuryakanth Sekar         }
656d509eb91SSuryakanth Sekar         auto ethIP = ethdevice + "/ipv6";
657d509eb91SSuryakanth Sekar         auto objectInfo =
658d509eb91SSuryakanth Sekar             getDbusObject(dbus, networkIPIntf, networkRoot, ethIP);
659d509eb91SSuryakanth Sekar         auto properties = getAllDbusProperties(dbus, objectInfo.second,
660d509eb91SSuryakanth Sekar                                                objectInfo.first, networkIPIntf);
661d509eb91SSuryakanth Sekar         if (sdbusplus::message::variant_ns::get<std::string>(
662d509eb91SSuryakanth Sekar                 properties["Origin"]) ==
663d509eb91SSuryakanth Sekar             "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
664d509eb91SSuryakanth Sekar         {
665d509eb91SSuryakanth Sekar             return true;
666d509eb91SSuryakanth Sekar         }
667d509eb91SSuryakanth Sekar         else
668d509eb91SSuryakanth Sekar         {
669d509eb91SSuryakanth Sekar             return false;
670d509eb91SSuryakanth Sekar         }
671d509eb91SSuryakanth Sekar     }
672d509eb91SSuryakanth Sekar     catch (sdbusplus::exception_t& e)
673d509eb91SSuryakanth Sekar     {
674d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
675d509eb91SSuryakanth Sekar         return true;
676d509eb91SSuryakanth Sekar     }
677d509eb91SSuryakanth Sekar }
678d509eb91SSuryakanth Sekar 
679d509eb91SSuryakanth Sekar /** @brief implementes the creating of default new user
680d509eb91SSuryakanth Sekar  *  @param[in] userName - new username in 16 bytes.
681d509eb91SSuryakanth Sekar  *  @param[in] userPassword - new password in 20 bytes
682d509eb91SSuryakanth Sekar  *  @returns ipmi completion code.
683d509eb91SSuryakanth Sekar  */
684d509eb91SSuryakanth Sekar ipmi::RspType<> ipmiOEMSetUser2Activation(
685d509eb91SSuryakanth Sekar     std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
686d509eb91SSuryakanth Sekar     std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
687d509eb91SSuryakanth Sekar {
688d509eb91SSuryakanth Sekar     bool userState = false;
689d509eb91SSuryakanth Sekar     // Check for System Interface not exist and LAN should be static
690d509eb91SSuryakanth Sekar     for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
691d509eb91SSuryakanth Sekar     {
692d509eb91SSuryakanth Sekar         ChannelInfo chInfo;
693d509eb91SSuryakanth Sekar         try
694d509eb91SSuryakanth Sekar         {
695d509eb91SSuryakanth Sekar             getChannelInfo(channel, chInfo);
696d509eb91SSuryakanth Sekar         }
697d509eb91SSuryakanth Sekar         catch (sdbusplus::exception_t& e)
698d509eb91SSuryakanth Sekar         {
699d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
700d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
701d509eb91SSuryakanth Sekar                 phosphor::logging::entry("MSG: %s", e.description()));
702d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccUnspecifiedError);
703d509eb91SSuryakanth Sekar         }
704d509eb91SSuryakanth Sekar         if (chInfo.mediumType ==
705d509eb91SSuryakanth Sekar             static_cast<uint8_t>(EChannelMediumType::systemInterface))
706d509eb91SSuryakanth Sekar         {
707d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
708d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: system interface  exist .");
709d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
710d509eb91SSuryakanth Sekar         }
711d509eb91SSuryakanth Sekar         else
712d509eb91SSuryakanth Sekar         {
713d509eb91SSuryakanth Sekar 
714d509eb91SSuryakanth Sekar             if (chInfo.mediumType ==
715d509eb91SSuryakanth Sekar                 static_cast<uint8_t>(EChannelMediumType::lan8032))
716d509eb91SSuryakanth Sekar             {
717d509eb91SSuryakanth Sekar                 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
718d509eb91SSuryakanth Sekar                 {
719d509eb91SSuryakanth Sekar                     phosphor::logging::log<phosphor::logging::level::ERR>(
720d509eb91SSuryakanth Sekar                         "ipmiOEMSetUser2Activation: DHCP enabled .");
721d509eb91SSuryakanth Sekar                     return ipmi::response(ipmi::ccCommandNotAvailable);
722d509eb91SSuryakanth Sekar                 }
723d509eb91SSuryakanth Sekar             }
724d509eb91SSuryakanth Sekar         }
725d509eb91SSuryakanth Sekar     }
726d509eb91SSuryakanth Sekar     uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
727d509eb91SSuryakanth Sekar     if (ipmi::ccSuccess ==
728d509eb91SSuryakanth Sekar         ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
729d509eb91SSuryakanth Sekar     {
730d509eb91SSuryakanth Sekar         if (enabledUsers > 1)
731d509eb91SSuryakanth Sekar         {
732d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
733d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: more than one user is enabled.");
734d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
735d509eb91SSuryakanth Sekar         }
736d509eb91SSuryakanth Sekar         // Check the user 2 is enabled or not
737d509eb91SSuryakanth Sekar         ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
738d509eb91SSuryakanth Sekar         if (userState == true)
739d509eb91SSuryakanth Sekar         {
740d509eb91SSuryakanth Sekar             phosphor::logging::log<phosphor::logging::level::ERR>(
741d509eb91SSuryakanth Sekar                 "ipmiOEMSetUser2Activation: user 2 already enabled .");
742d509eb91SSuryakanth Sekar             return ipmi::response(ipmi::ccCommandNotAvailable);
743d509eb91SSuryakanth Sekar         }
744d509eb91SSuryakanth Sekar     }
745d509eb91SSuryakanth Sekar     else
746d509eb91SSuryakanth Sekar     {
747d509eb91SSuryakanth Sekar         return ipmi::response(ipmi::ccUnspecifiedError);
748d509eb91SSuryakanth Sekar     }
749d509eb91SSuryakanth Sekar 
750d509eb91SSuryakanth Sekar #if BYTE_ORDER == LITTLE_ENDIAN
751d509eb91SSuryakanth Sekar     PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
752d509eb91SSuryakanth Sekar #endif
753d509eb91SSuryakanth Sekar #if BYTE_ORDER == BIG_ENDIAN
754d509eb91SSuryakanth Sekar     PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
755d509eb91SSuryakanth Sekar #endif
756d509eb91SSuryakanth Sekar 
757d509eb91SSuryakanth Sekar     if (ipmi::ccSuccess ==
758d509eb91SSuryakanth Sekar         ipmiUserSetUserName(ipmiDefaultUserId,
759d509eb91SSuryakanth Sekar                             reinterpret_cast<const char*>(userName.data())))
760d509eb91SSuryakanth Sekar     {
761d509eb91SSuryakanth Sekar         if (ipmi::ccSuccess ==
762d509eb91SSuryakanth Sekar             ipmiUserSetUserPassword(
763d509eb91SSuryakanth Sekar                 ipmiDefaultUserId,
764d509eb91SSuryakanth Sekar                 reinterpret_cast<const char*>(userPassword.data())))
765d509eb91SSuryakanth Sekar         {
766d509eb91SSuryakanth Sekar             if (ipmi::ccSuccess ==
767d509eb91SSuryakanth Sekar                 ipmiUserSetPrivilegeAccess(
768d509eb91SSuryakanth Sekar                     ipmiDefaultUserId,
769d509eb91SSuryakanth Sekar                     static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
770d509eb91SSuryakanth Sekar                     privAccess, true))
771d509eb91SSuryakanth Sekar             {
772d509eb91SSuryakanth Sekar                 phosphor::logging::log<phosphor::logging::level::INFO>(
773d509eb91SSuryakanth Sekar                     "ipmiOEMSetUser2Activation: user created successfully ");
774d509eb91SSuryakanth Sekar                 return ipmi::responseSuccess();
775d509eb91SSuryakanth Sekar             }
776d509eb91SSuryakanth Sekar         }
777d509eb91SSuryakanth Sekar         // we need to delete  the default user id which added in this command as
778d509eb91SSuryakanth Sekar         // password / priv setting is failed.
779d509eb91SSuryakanth Sekar         ipmiUserSetUserName(ipmiDefaultUserId, "");
780d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(
781d509eb91SSuryakanth Sekar             "ipmiOEMSetUser2Activation: password / priv setting is failed.");
782d509eb91SSuryakanth Sekar     }
783d509eb91SSuryakanth Sekar     else
784d509eb91SSuryakanth Sekar     {
785d509eb91SSuryakanth Sekar         phosphor::logging::log<phosphor::logging::level::ERR>(
786d509eb91SSuryakanth Sekar             "ipmiOEMSetUser2Activation: Setting username failed.");
787d509eb91SSuryakanth Sekar     }
788d509eb91SSuryakanth Sekar 
789d509eb91SSuryakanth Sekar     return ipmi::response(ipmi::ccCommandNotAvailable);
790d509eb91SSuryakanth Sekar }
791d509eb91SSuryakanth Sekar 
79245f04988SKuiying Wang namespace ledAction
79345f04988SKuiying Wang {
79445f04988SKuiying Wang using namespace sdbusplus::xyz::openbmc_project::Led::server;
79545f04988SKuiying Wang std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
79645f04988SKuiying Wang     {Physical::Action::Off, 0x00},
79745f04988SKuiying Wang     {Physical::Action::On, 0x10},
79845f04988SKuiying Wang     {Physical::Action::Blink, 0x01}};
79945f04988SKuiying Wang 
80045f04988SKuiying Wang std::map<uint8_t, std::string> offsetObjPath = {
80145f04988SKuiying Wang     {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
80245f04988SKuiying Wang 
80345f04988SKuiying Wang } // namespace ledAction
80445f04988SKuiying Wang 
80545f04988SKuiying Wang int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
80645f04988SKuiying Wang                    const std::string& objPath, uint8_t& state)
80745f04988SKuiying Wang {
80845f04988SKuiying Wang     try
80945f04988SKuiying Wang     {
81045f04988SKuiying Wang         std::string service = getService(bus, intf, objPath);
81145f04988SKuiying Wang         Value stateValue =
81245f04988SKuiying Wang             getDbusProperty(bus, service, objPath, intf, "State");
81345f04988SKuiying Wang         std::string strState =
81445f04988SKuiying Wang             sdbusplus::message::variant_ns::get<std::string>(stateValue);
81545f04988SKuiying Wang         state = ledAction::actionDbusToIpmi.at(
81645f04988SKuiying Wang             sdbusplus::xyz::openbmc_project::Led::server::Physical::
81745f04988SKuiying Wang                 convertActionFromString(strState));
81845f04988SKuiying Wang     }
81945f04988SKuiying Wang     catch (sdbusplus::exception::SdBusError& e)
82045f04988SKuiying Wang     {
82145f04988SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
82245f04988SKuiying Wang         return -1;
82345f04988SKuiying Wang     }
82445f04988SKuiying Wang     return 0;
82545f04988SKuiying Wang }
82645f04988SKuiying Wang 
82745f04988SKuiying Wang ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
82845f04988SKuiying Wang                                ipmi_request_t request, ipmi_response_t response,
82945f04988SKuiying Wang                                ipmi_data_len_t dataLen, ipmi_context_t context)
83045f04988SKuiying Wang {
83145f04988SKuiying Wang     uint8_t* resp = reinterpret_cast<uint8_t*>(response);
83245f04988SKuiying Wang     // LED Status
83345f04988SKuiying Wang     //[1:0] = Reserved
83445f04988SKuiying Wang     //[3:2] = Status(Amber)
83545f04988SKuiying Wang     //[5:4] = Status(Green)
83645f04988SKuiying Wang     //[7:6] = System Identify
83745f04988SKuiying Wang     // Status definitions:
83845f04988SKuiying Wang     // 00b = Off
83945f04988SKuiying Wang     // 01b = Blink
84045f04988SKuiying Wang     // 10b = On
84145f04988SKuiying Wang     // 11b = invalid
84245f04988SKuiying Wang     if (*dataLen != 0)
84345f04988SKuiying Wang     {
84445f04988SKuiying Wang         phosphor::logging::log<phosphor::logging::level::ERR>(
84545f04988SKuiying Wang             "oem_get_led_status: invalid input len!");
84645f04988SKuiying Wang         *dataLen = 0;
84745f04988SKuiying Wang         return IPMI_CC_REQ_DATA_LEN_INVALID;
84845f04988SKuiying Wang     }
84945f04988SKuiying Wang 
85045f04988SKuiying Wang     phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
85145f04988SKuiying Wang     *resp = 0;
85245f04988SKuiying Wang     *dataLen = 0;
85345f04988SKuiying Wang     for (auto it = ledAction::offsetObjPath.begin();
85445f04988SKuiying Wang          it != ledAction::offsetObjPath.end(); ++it)
85545f04988SKuiying Wang     {
85645f04988SKuiying Wang         uint8_t state = 0;
85745f04988SKuiying Wang         if (-1 == getLEDState(dbus, ledIntf, it->second, state))
85845f04988SKuiying Wang         {
85945f04988SKuiying Wang             phosphor::logging::log<phosphor::logging::level::ERR>(
86045f04988SKuiying Wang                 "oem_get_led_status: fail to get ID LED status!");
86145f04988SKuiying Wang             return IPMI_CC_UNSPECIFIED_ERROR;
86245f04988SKuiying Wang         }
86345f04988SKuiying Wang         *resp |= state << it->first;
86445f04988SKuiying Wang     }
86545f04988SKuiying Wang 
86645f04988SKuiying Wang     *dataLen = sizeof(*resp);
86745f04988SKuiying Wang     return IPMI_CC_OK;
86845f04988SKuiying Wang }
86945f04988SKuiying Wang 
87023737fe3SYong Li ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
87123737fe3SYong Li                                          ipmi_request_t request,
87223737fe3SYong Li                                          ipmi_response_t response,
87323737fe3SYong Li                                          ipmi_data_len_t dataLen,
87423737fe3SYong Li                                          ipmi_context_t context)
87523737fe3SYong Li {
87623737fe3SYong Li     CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
87723737fe3SYong Li     uint8_t* resp = reinterpret_cast<uint8_t*>(response);
87823737fe3SYong Li 
87923737fe3SYong Li     if (*dataLen == 0)
88023737fe3SYong Li     {
88123737fe3SYong Li         phosphor::logging::log<phosphor::logging::level::ERR>(
88223737fe3SYong Li             "CfgHostSerial: invalid input len!",
88323737fe3SYong Li             phosphor::logging::entry("LEN=%d", *dataLen));
88423737fe3SYong Li         return IPMI_CC_REQ_DATA_LEN_INVALID;
88523737fe3SYong Li     }
88623737fe3SYong Li 
88723737fe3SYong Li     switch (req->command)
88823737fe3SYong Li     {
88923737fe3SYong Li         case getHostSerialCfgCmd:
89023737fe3SYong Li         {
89123737fe3SYong Li             if (*dataLen != 1)
89223737fe3SYong Li             {
89323737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
89423737fe3SYong Li                     "CfgHostSerial: invalid input len!");
89523737fe3SYong Li                 *dataLen = 0;
89623737fe3SYong Li                 return IPMI_CC_REQ_DATA_LEN_INVALID;
89723737fe3SYong Li             }
89823737fe3SYong Li 
89923737fe3SYong Li             *dataLen = 0;
90023737fe3SYong Li 
90123737fe3SYong Li             boost::process::ipstream is;
90223737fe3SYong Li             std::vector<std::string> data;
90323737fe3SYong Li             std::string line;
90423737fe3SYong Li             boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
90523737fe3SYong Li                                      boost::process::std_out > is);
90623737fe3SYong Li 
90723737fe3SYong Li             while (c1.running() && std::getline(is, line) && !line.empty())
90823737fe3SYong Li             {
90923737fe3SYong Li                 data.push_back(line);
91023737fe3SYong Li             }
91123737fe3SYong Li 
91223737fe3SYong Li             c1.wait();
91323737fe3SYong Li             if (c1.exit_code())
91423737fe3SYong Li             {
91523737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
91623737fe3SYong Li                     "CfgHostSerial:: error on execute",
91723737fe3SYong Li                     phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
91823737fe3SYong Li                 // Using the default value
91923737fe3SYong Li                 *resp = 0;
92023737fe3SYong Li             }
92123737fe3SYong Li             else
92223737fe3SYong Li             {
92323737fe3SYong Li                 if (data.size() != 1)
92423737fe3SYong Li                 {
92523737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
92623737fe3SYong Li                         "CfgHostSerial:: error on read env");
92723737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
92823737fe3SYong Li                 }
92923737fe3SYong Li                 try
93023737fe3SYong Li                 {
93123737fe3SYong Li                     unsigned long tmp = std::stoul(data[0]);
93223737fe3SYong Li                     if (tmp > std::numeric_limits<uint8_t>::max())
93323737fe3SYong Li                     {
93423737fe3SYong Li                         throw std::out_of_range("Out of range");
93523737fe3SYong Li                     }
93623737fe3SYong Li                     *resp = static_cast<uint8_t>(tmp);
93723737fe3SYong Li                 }
93823737fe3SYong Li                 catch (const std::invalid_argument& e)
93923737fe3SYong Li                 {
94023737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
94123737fe3SYong Li                         "invalid config ",
94223737fe3SYong Li                         phosphor::logging::entry("ERR=%s", e.what()));
94323737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
94423737fe3SYong Li                 }
94523737fe3SYong Li                 catch (const std::out_of_range& e)
94623737fe3SYong Li                 {
94723737fe3SYong Li                     phosphor::logging::log<phosphor::logging::level::ERR>(
94823737fe3SYong Li                         "out_of_range config ",
94923737fe3SYong Li                         phosphor::logging::entry("ERR=%s", e.what()));
95023737fe3SYong Li                     return IPMI_CC_UNSPECIFIED_ERROR;
95123737fe3SYong Li                 }
95223737fe3SYong Li             }
95323737fe3SYong Li 
95423737fe3SYong Li             *dataLen = 1;
95523737fe3SYong Li             break;
95623737fe3SYong Li         }
95723737fe3SYong Li         case setHostSerialCfgCmd:
95823737fe3SYong Li         {
95923737fe3SYong Li             if (*dataLen != sizeof(CfgHostSerialReq))
96023737fe3SYong Li             {
96123737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
96223737fe3SYong Li                     "CfgHostSerial: invalid input len!");
96323737fe3SYong Li                 *dataLen = 0;
96423737fe3SYong Li                 return IPMI_CC_REQ_DATA_LEN_INVALID;
96523737fe3SYong Li             }
96623737fe3SYong Li 
96723737fe3SYong Li             *dataLen = 0;
96823737fe3SYong Li 
96923737fe3SYong Li             if (req->parameter > HostSerialCfgParamMax)
97023737fe3SYong Li             {
97123737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
97223737fe3SYong Li                     "CfgHostSerial: invalid input!");
97323737fe3SYong Li                 return IPMI_CC_INVALID_FIELD_REQUEST;
97423737fe3SYong Li             }
97523737fe3SYong Li 
97623737fe3SYong Li             boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
97723737fe3SYong Li                                      std::to_string(req->parameter));
97823737fe3SYong Li 
97923737fe3SYong Li             c1.wait();
98023737fe3SYong Li             if (c1.exit_code())
98123737fe3SYong Li             {
98223737fe3SYong Li                 phosphor::logging::log<phosphor::logging::level::ERR>(
98323737fe3SYong Li                     "CfgHostSerial:: error on execute",
98423737fe3SYong Li                     phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
98523737fe3SYong Li                 return IPMI_CC_UNSPECIFIED_ERROR;
98623737fe3SYong Li             }
98723737fe3SYong Li             break;
98823737fe3SYong Li         }
98923737fe3SYong Li         default:
99023737fe3SYong Li             phosphor::logging::log<phosphor::logging::level::ERR>(
99123737fe3SYong Li                 "CfgHostSerial: invalid input!");
99223737fe3SYong Li             *dataLen = 0;
99323737fe3SYong Li             return IPMI_CC_INVALID_FIELD_REQUEST;
99423737fe3SYong Li     }
99523737fe3SYong Li 
99623737fe3SYong Li     return IPMI_CC_OK;
99723737fe3SYong Li }
99823737fe3SYong Li 
99991244a6aSJames Feist constexpr const char* thermalModeInterface =
100091244a6aSJames Feist     "xyz.openbmc_project.Control.ThermalMode";
100191244a6aSJames Feist constexpr const char* thermalModePath =
100291244a6aSJames Feist     "/xyz/openbmc_project/control/thermal_mode";
100391244a6aSJames Feist 
100491244a6aSJames Feist bool getFanProfileInterface(
100591244a6aSJames Feist     sdbusplus::bus::bus& bus,
100691244a6aSJames Feist     boost::container::flat_map<
100791244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>& resp)
100891244a6aSJames Feist {
100991244a6aSJames Feist     auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
101091244a6aSJames Feist                                     "GetAll");
101191244a6aSJames Feist     call.append(thermalModeInterface);
101291244a6aSJames Feist     try
101391244a6aSJames Feist     {
101491244a6aSJames Feist         auto data = bus.call(call);
101591244a6aSJames Feist         data.read(resp);
101691244a6aSJames Feist     }
101791244a6aSJames Feist     catch (sdbusplus::exception_t& e)
101891244a6aSJames Feist     {
101991244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
102091244a6aSJames Feist             "getFanProfileInterface: can't get thermal mode!",
102191244a6aSJames Feist             phosphor::logging::entry("ERR=%s", e.what()));
102291244a6aSJames Feist         return false;
102391244a6aSJames Feist     }
102491244a6aSJames Feist     return true;
102591244a6aSJames Feist }
102691244a6aSJames Feist 
102791244a6aSJames Feist ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
102891244a6aSJames Feist                                ipmi_request_t request, ipmi_response_t response,
102991244a6aSJames Feist                                ipmi_data_len_t dataLen, ipmi_context_t context)
103091244a6aSJames Feist {
103191244a6aSJames Feist 
103291244a6aSJames Feist     if (*dataLen < 2 || *dataLen > 7)
103391244a6aSJames Feist     {
103491244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
103591244a6aSJames Feist             "ipmiOEMSetFanConfig: invalid input len!");
103691244a6aSJames Feist         *dataLen = 0;
103791244a6aSJames Feist         return IPMI_CC_REQ_DATA_LEN_INVALID;
103891244a6aSJames Feist     }
103991244a6aSJames Feist 
104091244a6aSJames Feist     // todo: tell bios to only send first 2 bytes
104191244a6aSJames Feist 
104291244a6aSJames Feist     SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
104391244a6aSJames Feist     boost::container::flat_map<
104491244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>
104591244a6aSJames Feist         profileData;
104691244a6aSJames Feist     if (!getFanProfileInterface(dbus, profileData))
104791244a6aSJames Feist     {
104891244a6aSJames Feist         return IPMI_CC_UNSPECIFIED_ERROR;
104991244a6aSJames Feist     }
105091244a6aSJames Feist 
105191244a6aSJames Feist     std::vector<std::string>* supported =
105291244a6aSJames Feist         std::get_if<std::vector<std::string>>(&profileData["Supported"]);
105391244a6aSJames Feist     if (supported == nullptr)
105491244a6aSJames Feist     {
105591244a6aSJames Feist         return IPMI_CC_INVALID_FIELD_REQUEST;
105691244a6aSJames Feist     }
105791244a6aSJames Feist     std::string mode;
105891244a6aSJames Feist     if (req->flags &
105991244a6aSJames Feist         (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
106091244a6aSJames Feist     {
106191244a6aSJames Feist         bool performanceMode =
106291244a6aSJames Feist             (req->flags & (1 << static_cast<uint8_t>(
106391244a6aSJames Feist                                setFanProfileFlags::performAcousSelect))) > 0;
106491244a6aSJames Feist 
106591244a6aSJames Feist         if (performanceMode)
106691244a6aSJames Feist         {
106791244a6aSJames Feist 
106891244a6aSJames Feist             if (std::find(supported->begin(), supported->end(),
106991244a6aSJames Feist                           "Performance") != supported->end())
107091244a6aSJames Feist             {
107191244a6aSJames Feist                 mode = "Performance";
107291244a6aSJames Feist             }
107391244a6aSJames Feist         }
107491244a6aSJames Feist         else
107591244a6aSJames Feist         {
107691244a6aSJames Feist 
107791244a6aSJames Feist             if (std::find(supported->begin(), supported->end(), "Acoustic") !=
107891244a6aSJames Feist                 supported->end())
107991244a6aSJames Feist             {
108091244a6aSJames Feist                 mode = "Acoustic";
108191244a6aSJames Feist             }
108291244a6aSJames Feist         }
108391244a6aSJames Feist         if (mode.empty())
108491244a6aSJames Feist         {
108591244a6aSJames Feist             return IPMI_CC_INVALID_FIELD_REQUEST;
108691244a6aSJames Feist         }
108791244a6aSJames Feist         setDbusProperty(dbus, settingsBusName, thermalModePath,
108891244a6aSJames Feist                         thermalModeInterface, "Current", mode);
108991244a6aSJames Feist     }
109091244a6aSJames Feist 
109191244a6aSJames Feist     return IPMI_CC_OK;
109291244a6aSJames Feist }
109391244a6aSJames Feist 
109491244a6aSJames Feist ipmi_ret_t ipmiOEMGetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
109591244a6aSJames Feist                                ipmi_request_t request, ipmi_response_t response,
109691244a6aSJames Feist                                ipmi_data_len_t dataLen, ipmi_context_t context)
109791244a6aSJames Feist {
109891244a6aSJames Feist 
109991244a6aSJames Feist     if (*dataLen > 1)
110091244a6aSJames Feist     {
110191244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
110291244a6aSJames Feist             "ipmiOEMGetFanConfig: invalid input len!");
110391244a6aSJames Feist         *dataLen = 0;
110491244a6aSJames Feist         return IPMI_CC_REQ_DATA_LEN_INVALID;
110591244a6aSJames Feist     }
110691244a6aSJames Feist 
110791244a6aSJames Feist     // todo: talk to bios about needing less information
110891244a6aSJames Feist 
110991244a6aSJames Feist     GetFanConfigResp* resp = reinterpret_cast<GetFanConfigResp*>(response);
111091244a6aSJames Feist     *dataLen = sizeof(GetFanConfigResp);
111191244a6aSJames Feist 
111291244a6aSJames Feist     boost::container::flat_map<
111391244a6aSJames Feist         std::string, std::variant<std::vector<std::string>, std::string>>
111491244a6aSJames Feist         profileData;
111591244a6aSJames Feist 
111691244a6aSJames Feist     if (!getFanProfileInterface(dbus, profileData))
111791244a6aSJames Feist     {
111891244a6aSJames Feist         return IPMI_CC_UNSPECIFIED_ERROR;
111991244a6aSJames Feist     }
112091244a6aSJames Feist 
112191244a6aSJames Feist     std::string* current = std::get_if<std::string>(&profileData["Current"]);
112291244a6aSJames Feist 
112391244a6aSJames Feist     if (current == nullptr)
112491244a6aSJames Feist     {
112591244a6aSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
112691244a6aSJames Feist             "ipmiOEMGetFanConfig: can't get current mode!");
112791244a6aSJames Feist         return IPMI_CC_UNSPECIFIED_ERROR;
112891244a6aSJames Feist     }
112991244a6aSJames Feist     bool performance = (*current == "Performance");
113091244a6aSJames Feist 
113191244a6aSJames Feist     if (performance)
113291244a6aSJames Feist     {
113391244a6aSJames Feist         resp->flags |= 1 << 2;
113491244a6aSJames Feist     }
113591244a6aSJames Feist 
113691244a6aSJames Feist     return IPMI_CC_OK;
113791244a6aSJames Feist }
113891244a6aSJames Feist 
11395f957cafSJames Feist constexpr const char* cfmLimitSettingPath =
11405f957cafSJames Feist     "/xyz/openbmc_project/control/cfm_limit";
11415f957cafSJames Feist constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
1142faa4f223SJames Feist constexpr const size_t legacyExitAirSensorNumber = 0x2e;
1143*acc8a4ebSJames Feist constexpr const char* pidConfigurationIface =
1144*acc8a4ebSJames Feist     "xyz.openbmc_project.Configuration.Pid";
1145faa4f223SJames Feist 
1146faa4f223SJames Feist static std::string getExitAirConfigPath()
1147faa4f223SJames Feist {
1148faa4f223SJames Feist 
1149faa4f223SJames Feist     auto method =
1150faa4f223SJames Feist         dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
1151faa4f223SJames Feist                              "/xyz/openbmc_project/object_mapper",
1152faa4f223SJames Feist                              "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1153faa4f223SJames Feist 
1154*acc8a4ebSJames Feist     method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1155faa4f223SJames Feist     std::string path;
1156faa4f223SJames Feist     GetSubTreeType resp;
1157faa4f223SJames Feist     try
1158faa4f223SJames Feist     {
1159faa4f223SJames Feist         auto reply = dbus.call(method);
1160faa4f223SJames Feist         reply.read(resp);
1161faa4f223SJames Feist     }
1162faa4f223SJames Feist     catch (sdbusplus::exception_t&)
1163faa4f223SJames Feist     {
1164faa4f223SJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1165faa4f223SJames Feist             "ipmiOEMGetFscParameter: mapper error");
1166faa4f223SJames Feist     };
1167faa4f223SJames Feist     auto config = std::find_if(resp.begin(), resp.end(), [](const auto& pair) {
1168faa4f223SJames Feist         return pair.first.find("Exit_Air") != std::string::npos;
1169faa4f223SJames Feist     });
1170faa4f223SJames Feist     if (config != resp.end())
1171faa4f223SJames Feist     {
1172faa4f223SJames Feist         path = std::move(config->first);
1173faa4f223SJames Feist     }
1174faa4f223SJames Feist     return path;
1175faa4f223SJames Feist }
11765f957cafSJames Feist 
1177*acc8a4ebSJames Feist // flat map to make alphabetical
1178*acc8a4ebSJames Feist static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1179*acc8a4ebSJames Feist {
1180*acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> ret;
1181*acc8a4ebSJames Feist     auto method =
1182*acc8a4ebSJames Feist         dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
1183*acc8a4ebSJames Feist                              "/xyz/openbmc_project/object_mapper",
1184*acc8a4ebSJames Feist                              "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1185*acc8a4ebSJames Feist 
1186*acc8a4ebSJames Feist     method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1187*acc8a4ebSJames Feist     GetSubTreeType resp;
1188*acc8a4ebSJames Feist 
1189*acc8a4ebSJames Feist     try
1190*acc8a4ebSJames Feist     {
1191*acc8a4ebSJames Feist         auto reply = dbus.call(method);
1192*acc8a4ebSJames Feist         reply.read(resp);
1193*acc8a4ebSJames Feist     }
1194*acc8a4ebSJames Feist     catch (sdbusplus::exception_t&)
1195*acc8a4ebSJames Feist     {
1196*acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1197*acc8a4ebSJames Feist             "getFanConfigPaths: mapper error");
1198*acc8a4ebSJames Feist     };
1199*acc8a4ebSJames Feist     for (const auto& [path, objects] : resp)
1200*acc8a4ebSJames Feist     {
1201*acc8a4ebSJames Feist         if (objects.empty())
1202*acc8a4ebSJames Feist         {
1203*acc8a4ebSJames Feist             continue; // should be impossible
1204*acc8a4ebSJames Feist         }
1205*acc8a4ebSJames Feist         ret.emplace(path, getAllDbusProperties(dbus, objects[0].first, path,
1206*acc8a4ebSJames Feist                                                pidConfigurationIface));
1207*acc8a4ebSJames Feist     }
1208*acc8a4ebSJames Feist     return ret;
1209*acc8a4ebSJames Feist }
1210*acc8a4ebSJames Feist 
1211*acc8a4ebSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1212*acc8a4ebSJames Feist {
1213*acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1214*acc8a4ebSJames Feist     if (data.empty())
1215*acc8a4ebSJames Feist     {
1216*acc8a4ebSJames Feist         return ipmi::responseResponseError();
1217*acc8a4ebSJames Feist     }
1218*acc8a4ebSJames Feist     uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1219*acc8a4ebSJames Feist     for (const auto& [_, pid] : data)
1220*acc8a4ebSJames Feist     {
1221*acc8a4ebSJames Feist         auto findClass = pid.find("Class");
1222*acc8a4ebSJames Feist         if (findClass == pid.end())
1223*acc8a4ebSJames Feist         {
1224*acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1225*acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: found illegal pid "
1226*acc8a4ebSJames Feist                 "configurations");
1227*acc8a4ebSJames Feist             return ipmi::responseResponseError();
1228*acc8a4ebSJames Feist         }
1229*acc8a4ebSJames Feist         std::string type = std::get<std::string>(findClass->second);
1230*acc8a4ebSJames Feist         if (type == "fan")
1231*acc8a4ebSJames Feist         {
1232*acc8a4ebSJames Feist             auto findOutLimit = pid.find("OutLimitMin");
1233*acc8a4ebSJames Feist             if (findOutLimit == pid.end())
1234*acc8a4ebSJames Feist             {
1235*acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1236*acc8a4ebSJames Feist                     "ipmiOEMGetFscParameter: found illegal pid "
1237*acc8a4ebSJames Feist                     "configurations");
1238*acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1239*acc8a4ebSJames Feist             }
1240*acc8a4ebSJames Feist             // get the min out of all the offsets
1241*acc8a4ebSJames Feist             minOffset = std::min(
1242*acc8a4ebSJames Feist                 minOffset,
1243*acc8a4ebSJames Feist                 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1244*acc8a4ebSJames Feist         }
1245*acc8a4ebSJames Feist     }
1246*acc8a4ebSJames Feist     if (minOffset == std::numeric_limits<uint8_t>::max())
1247*acc8a4ebSJames Feist     {
1248*acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1249*acc8a4ebSJames Feist             "ipmiOEMGetFscParameter: found no fan configurations!");
1250*acc8a4ebSJames Feist         return ipmi::responseResponseError();
1251*acc8a4ebSJames Feist     }
1252*acc8a4ebSJames Feist 
1253*acc8a4ebSJames Feist     return ipmi::responseSuccess(minOffset);
1254*acc8a4ebSJames Feist }
1255*acc8a4ebSJames Feist 
1256*acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1257*acc8a4ebSJames Feist {
1258*acc8a4ebSJames Feist     boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1259*acc8a4ebSJames Feist     if (data.empty())
1260*acc8a4ebSJames Feist     {
1261*acc8a4ebSJames Feist 
1262*acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1263*acc8a4ebSJames Feist             "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1264*acc8a4ebSJames Feist         return ipmi::responseResponseError();
1265*acc8a4ebSJames Feist     }
1266*acc8a4ebSJames Feist 
1267*acc8a4ebSJames Feist     bool found = false;
1268*acc8a4ebSJames Feist     for (const auto& [path, pid] : data)
1269*acc8a4ebSJames Feist     {
1270*acc8a4ebSJames Feist         auto findClass = pid.find("Class");
1271*acc8a4ebSJames Feist         if (findClass == pid.end())
1272*acc8a4ebSJames Feist         {
1273*acc8a4ebSJames Feist 
1274*acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1275*acc8a4ebSJames Feist                 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1276*acc8a4ebSJames Feist                 "configurations");
1277*acc8a4ebSJames Feist             return ipmi::responseResponseError();
1278*acc8a4ebSJames Feist         }
1279*acc8a4ebSJames Feist         std::string type = std::get<std::string>(findClass->second);
1280*acc8a4ebSJames Feist         if (type == "fan")
1281*acc8a4ebSJames Feist         {
1282*acc8a4ebSJames Feist             auto findOutLimit = pid.find("OutLimitMin");
1283*acc8a4ebSJames Feist             if (findOutLimit == pid.end())
1284*acc8a4ebSJames Feist             {
1285*acc8a4ebSJames Feist 
1286*acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1287*acc8a4ebSJames Feist                     "ipmiOEMSetFanSpeedOffset: found illegal pid "
1288*acc8a4ebSJames Feist                     "configurations");
1289*acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1290*acc8a4ebSJames Feist             }
1291*acc8a4ebSJames Feist             ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
1292*acc8a4ebSJames Feist                                   path, pidConfigurationIface, "OutLimitMin",
1293*acc8a4ebSJames Feist                                   static_cast<double>(offset));
1294*acc8a4ebSJames Feist             found = true;
1295*acc8a4ebSJames Feist         }
1296*acc8a4ebSJames Feist     }
1297*acc8a4ebSJames Feist     if (!found)
1298*acc8a4ebSJames Feist     {
1299*acc8a4ebSJames Feist         phosphor::logging::log<phosphor::logging::level::ERR>(
1300*acc8a4ebSJames Feist             "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1301*acc8a4ebSJames Feist         return ipmi::responseResponseError();
1302*acc8a4ebSJames Feist     }
1303*acc8a4ebSJames Feist 
1304*acc8a4ebSJames Feist     return ipmi::responseSuccess();
1305*acc8a4ebSJames Feist }
1306*acc8a4ebSJames Feist 
1307*acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1308*acc8a4ebSJames Feist                                        uint8_t param2)
13095f957cafSJames Feist {
13105f957cafSJames Feist     constexpr const size_t disableLimiting = 0x0;
13115f957cafSJames Feist 
1312*acc8a4ebSJames Feist     if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
13135f957cafSJames Feist     {
1314*acc8a4ebSJames Feist         if (param1 == legacyExitAirSensorNumber)
1315faa4f223SJames Feist         {
1316faa4f223SJames Feist             std::string path = getExitAirConfigPath();
1317faa4f223SJames Feist             ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
1318*acc8a4ebSJames Feist                                   path, pidConfigurationIface, "SetPoint",
1319*acc8a4ebSJames Feist                                   static_cast<double>(param2));
1320*acc8a4ebSJames Feist             return ipmi::responseSuccess();
1321faa4f223SJames Feist         }
1322faa4f223SJames Feist         else
1323faa4f223SJames Feist         {
1324*acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
1325faa4f223SJames Feist         }
1326faa4f223SJames Feist     }
1327*acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
13285f957cafSJames Feist     {
1329*acc8a4ebSJames Feist         uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
13305f957cafSJames Feist 
13315f957cafSJames Feist         // must be greater than 50 based on eps
13325f957cafSJames Feist         if (cfm < 50 && cfm != disableLimiting)
13335f957cafSJames Feist         {
1334*acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
13355f957cafSJames Feist         }
13365f957cafSJames Feist 
13375f957cafSJames Feist         try
13385f957cafSJames Feist         {
13395f957cafSJames Feist             ipmi::setDbusProperty(dbus, settingsBusName, cfmLimitSettingPath,
13405f957cafSJames Feist                                   cfmLimitIface, "Limit",
13415f957cafSJames Feist                                   static_cast<double>(cfm));
13425f957cafSJames Feist         }
13435f957cafSJames Feist         catch (sdbusplus::exception_t& e)
13445f957cafSJames Feist         {
13455f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
13465f957cafSJames Feist                 "ipmiOEMSetFscParameter: can't set cfm setting!",
13475f957cafSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
1348*acc8a4ebSJames Feist             return ipmi::responseResponseError();
13495f957cafSJames Feist         }
1350*acc8a4ebSJames Feist         return ipmi::responseSuccess();
1351*acc8a4ebSJames Feist     }
1352*acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1353*acc8a4ebSJames Feist     {
1354*acc8a4ebSJames Feist         constexpr const size_t maxDomainCount = 8;
1355*acc8a4ebSJames Feist         uint8_t requestedDomainMask = param1;
1356*acc8a4ebSJames Feist         boost::container::flat_map data = getPidConfigs();
1357*acc8a4ebSJames Feist         if (data.empty())
1358*acc8a4ebSJames Feist         {
1359*acc8a4ebSJames Feist 
1360*acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1361*acc8a4ebSJames Feist                 "ipmiOEMSetFscParameter: found no pid configurations!");
1362*acc8a4ebSJames Feist             return ipmi::responseResponseError();
1363*acc8a4ebSJames Feist         }
1364*acc8a4ebSJames Feist         size_t count = 0;
1365*acc8a4ebSJames Feist         for (const auto& [path, pid] : data)
1366*acc8a4ebSJames Feist         {
1367*acc8a4ebSJames Feist             auto findClass = pid.find("Class");
1368*acc8a4ebSJames Feist             if (findClass == pid.end())
1369*acc8a4ebSJames Feist             {
1370*acc8a4ebSJames Feist 
1371*acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1372*acc8a4ebSJames Feist                     "ipmiOEMSetFscParameter: found illegal pid "
1373*acc8a4ebSJames Feist                     "configurations");
1374*acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1375*acc8a4ebSJames Feist             }
1376*acc8a4ebSJames Feist             std::string type = std::get<std::string>(findClass->second);
1377*acc8a4ebSJames Feist             if (type == "fan")
1378*acc8a4ebSJames Feist             {
1379*acc8a4ebSJames Feist                 if (requestedDomainMask & (1 << count))
1380*acc8a4ebSJames Feist                 {
1381*acc8a4ebSJames Feist                     ipmi::setDbusProperty(
1382*acc8a4ebSJames Feist                         dbus, "xyz.openbmc_project.EntityManager", path,
1383*acc8a4ebSJames Feist                         pidConfigurationIface, "OutLimitMax",
1384*acc8a4ebSJames Feist                         static_cast<double>(param2));
1385*acc8a4ebSJames Feist                 }
1386*acc8a4ebSJames Feist                 count++;
1387*acc8a4ebSJames Feist             }
1388*acc8a4ebSJames Feist         }
1389*acc8a4ebSJames Feist         return ipmi::responseSuccess();
13905f957cafSJames Feist     }
13915f957cafSJames Feist     else
13925f957cafSJames Feist     {
13935f957cafSJames Feist         // todo other command parts possibly
13945f957cafSJames Feist         // tcontrol is handled in peci now
13955f957cafSJames Feist         // fan speed offset not implemented yet
13965f957cafSJames Feist         // domain pwm limit not implemented
1397*acc8a4ebSJames Feist         return ipmi::responseParmOutOfRange();
13985f957cafSJames Feist     }
13995f957cafSJames Feist }
14005f957cafSJames Feist 
1401*acc8a4ebSJames Feist ipmi::RspType<
1402*acc8a4ebSJames Feist     std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1403*acc8a4ebSJames Feist     ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
14045f957cafSJames Feist {
1405faa4f223SJames Feist     constexpr uint8_t legacyDefaultExitAirLimit = -128;
14065f957cafSJames Feist 
1407*acc8a4ebSJames Feist     if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
14085f957cafSJames Feist     {
1409*acc8a4ebSJames Feist         if (!param)
1410*acc8a4ebSJames Feist         {
1411*acc8a4ebSJames Feist             return ipmi::responseReqDataLenInvalid();
14125f957cafSJames Feist         }
14135f957cafSJames Feist 
1414*acc8a4ebSJames Feist         if (*param != legacyExitAirSensorNumber)
1415faa4f223SJames Feist         {
1416*acc8a4ebSJames Feist             return ipmi::responseParmOutOfRange();
1417faa4f223SJames Feist         }
1418faa4f223SJames Feist         uint8_t setpoint = legacyDefaultExitAirLimit;
1419faa4f223SJames Feist         std::string path = getExitAirConfigPath();
1420faa4f223SJames Feist         if (path.size())
1421faa4f223SJames Feist         {
1422*acc8a4ebSJames Feist             Value val =
1423*acc8a4ebSJames Feist                 ipmi::getDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
1424*acc8a4ebSJames Feist                                       path, pidConfigurationIface, "SetPoint");
1425faa4f223SJames Feist             setpoint = std::floor(std::get<double>(val) + 0.5);
1426faa4f223SJames Feist         }
1427faa4f223SJames Feist 
1428faa4f223SJames Feist         // old implementation used to return the "default" and current, we
1429faa4f223SJames Feist         // don't make the default readily available so just make both the
1430faa4f223SJames Feist         // same
1431faa4f223SJames Feist 
1432*acc8a4ebSJames Feist         return ipmi::responseSuccess(
1433*acc8a4ebSJames Feist             std::array<uint8_t, 2>{setpoint, setpoint});
1434faa4f223SJames Feist     }
1435*acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1436*acc8a4ebSJames Feist     {
1437*acc8a4ebSJames Feist         constexpr const size_t maxDomainCount = 8;
1438*acc8a4ebSJames Feist 
1439*acc8a4ebSJames Feist         if (!param)
1440*acc8a4ebSJames Feist         {
1441*acc8a4ebSJames Feist             return ipmi::responseReqDataLenInvalid();
1442*acc8a4ebSJames Feist         }
1443*acc8a4ebSJames Feist         uint8_t requestedDomain = *param;
1444*acc8a4ebSJames Feist         if (requestedDomain >= maxDomainCount)
1445*acc8a4ebSJames Feist         {
1446*acc8a4ebSJames Feist             return ipmi::responseInvalidFieldRequest();
1447*acc8a4ebSJames Feist         }
1448*acc8a4ebSJames Feist 
1449*acc8a4ebSJames Feist         boost::container::flat_map data = getPidConfigs();
1450*acc8a4ebSJames Feist         if (data.empty())
1451*acc8a4ebSJames Feist         {
1452*acc8a4ebSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1453*acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: found no pid configurations!");
1454*acc8a4ebSJames Feist             return ipmi::responseResponseError();
1455*acc8a4ebSJames Feist         }
1456*acc8a4ebSJames Feist         size_t count = 0;
1457*acc8a4ebSJames Feist         for (const auto& [_, pid] : data)
1458*acc8a4ebSJames Feist         {
1459*acc8a4ebSJames Feist             auto findClass = pid.find("Class");
1460*acc8a4ebSJames Feist             if (findClass == pid.end())
1461*acc8a4ebSJames Feist             {
1462*acc8a4ebSJames Feist                 phosphor::logging::log<phosphor::logging::level::ERR>(
1463*acc8a4ebSJames Feist                     "ipmiOEMGetFscParameter: found illegal pid "
1464*acc8a4ebSJames Feist                     "configurations");
1465*acc8a4ebSJames Feist                 return ipmi::responseResponseError();
1466*acc8a4ebSJames Feist             }
1467*acc8a4ebSJames Feist             std::string type = std::get<std::string>(findClass->second);
1468*acc8a4ebSJames Feist             if (type == "fan")
1469*acc8a4ebSJames Feist             {
1470*acc8a4ebSJames Feist                 if (requestedDomain == count)
1471*acc8a4ebSJames Feist                 {
1472*acc8a4ebSJames Feist                     auto findOutLimit = pid.find("OutLimitMax");
1473*acc8a4ebSJames Feist                     if (findOutLimit == pid.end())
1474*acc8a4ebSJames Feist                     {
1475*acc8a4ebSJames Feist                         phosphor::logging::log<phosphor::logging::level::ERR>(
1476*acc8a4ebSJames Feist                             "ipmiOEMGetFscParameter: found illegal pid "
1477*acc8a4ebSJames Feist                             "configurations");
1478*acc8a4ebSJames Feist                         return ipmi::responseResponseError();
1479*acc8a4ebSJames Feist                     }
1480*acc8a4ebSJames Feist 
1481*acc8a4ebSJames Feist                     return ipmi::responseSuccess(
1482*acc8a4ebSJames Feist                         static_cast<uint8_t>(std::floor(
1483*acc8a4ebSJames Feist                             std::get<double>(findOutLimit->second) + 0.5)));
1484*acc8a4ebSJames Feist                 }
1485*acc8a4ebSJames Feist                 else
1486*acc8a4ebSJames Feist                 {
1487*acc8a4ebSJames Feist                     count++;
1488*acc8a4ebSJames Feist                 }
1489*acc8a4ebSJames Feist             }
1490*acc8a4ebSJames Feist         }
1491*acc8a4ebSJames Feist 
1492*acc8a4ebSJames Feist         return ipmi::responseInvalidFieldRequest();
1493*acc8a4ebSJames Feist     }
1494*acc8a4ebSJames Feist     else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
14955f957cafSJames Feist     {
14965f957cafSJames Feist 
14975f957cafSJames Feist         /*
14985f957cafSJames Feist         DataLen should be 1, but host is sending us an extra bit. As the
1499*acc8a4ebSJames Feist         previous behavior didn't seem to prevent this, ignore the check for
1500*acc8a4ebSJames Feist         now.
15015f957cafSJames Feist 
1502*acc8a4ebSJames Feist         if (param)
15035f957cafSJames Feist         {
15045f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
15055f957cafSJames Feist                 "ipmiOEMGetFscParameter: invalid input len!");
15065f957cafSJames Feist             return IPMI_CC_REQ_DATA_LEN_INVALID;
15075f957cafSJames Feist         }
15085f957cafSJames Feist         */
15095f957cafSJames Feist         Value cfmLimit;
15105f957cafSJames Feist         Value cfmMaximum;
15115f957cafSJames Feist         try
15125f957cafSJames Feist         {
15135f957cafSJames Feist             cfmLimit = ipmi::getDbusProperty(dbus, settingsBusName,
15145f957cafSJames Feist                                              cfmLimitSettingPath, cfmLimitIface,
15155f957cafSJames Feist                                              "Limit");
15165f957cafSJames Feist             cfmMaximum = ipmi::getDbusProperty(
15175f957cafSJames Feist                 dbus, "xyz.openbmc_project.ExitAirTempSensor",
15185f957cafSJames Feist                 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
15195f957cafSJames Feist         }
15205f957cafSJames Feist         catch (sdbusplus::exception_t& e)
15215f957cafSJames Feist         {
15225f957cafSJames Feist             phosphor::logging::log<phosphor::logging::level::ERR>(
1523*acc8a4ebSJames Feist                 "ipmiOEMGetFscParameter: can't get cfm setting!",
15245f957cafSJames Feist                 phosphor::logging::entry("ERR=%s", e.what()));
1525*acc8a4ebSJames Feist             return ipmi::responseResponseError();
15265f957cafSJames Feist         }
15275f957cafSJames Feist 
1528*acc8a4ebSJames Feist         double cfmMax = std::get<double>(cfmMaximum);
1529*acc8a4ebSJames Feist         double cfmLim = std::get<double>(cfmLimit);
1530*acc8a4ebSJames Feist 
1531*acc8a4ebSJames Feist         cfmLim = std::floor(cfmLim + 0.5);
1532*acc8a4ebSJames Feist         cfmMax = std::floor(cfmMax + 0.5);
1533*acc8a4ebSJames Feist         uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1534*acc8a4ebSJames Feist         uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
1535*acc8a4ebSJames Feist 
1536*acc8a4ebSJames Feist         return ipmi::responseSuccess(
1537*acc8a4ebSJames Feist             std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
15385f957cafSJames Feist     }
15395f957cafSJames Feist 
15405f957cafSJames Feist     else
15415f957cafSJames Feist     {
15425f957cafSJames Feist         // todo other command parts possibly
15435f957cafSJames Feist         // domain pwm limit not implemented
1544*acc8a4ebSJames Feist         return ipmi::responseParmOutOfRange();
15455f957cafSJames Feist     }
15465f957cafSJames Feist }
15475f957cafSJames Feist 
154864796041SJason M. Bills static void registerOEMFunctions(void)
1549a835eaa0SJia, Chunhui {
1550a835eaa0SJia, Chunhui     phosphor::logging::log<phosphor::logging::level::INFO>(
1551a835eaa0SJia, Chunhui         "Registering OEM commands");
155264796041SJason M. Bills     ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
1553a835eaa0SJia, Chunhui                          ipmiOEMWildcard,
1554a835eaa0SJia, Chunhui                          PRIVILEGE_USER); // wildcard default handler
155564796041SJason M. Bills     ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
155664796041SJason M. Bills                          ipmiOEMWildcard,
155764796041SJason M. Bills                          PRIVILEGE_USER); // wildcard default handler
155864796041SJason M. Bills     ipmiPrintAndRegister(
155964796041SJason M. Bills         netfnIntcOEMGeneral,
156064796041SJason M. Bills         static_cast<ipmi_cmd_t>(
156164796041SJason M. Bills             IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
156264796041SJason M. Bills         NULL, ipmiOEMGetChassisIdentifier,
1563a835eaa0SJia, Chunhui         PRIVILEGE_USER); // get chassis identifier
156464796041SJason M. Bills     ipmiPrintAndRegister(
156564796041SJason M. Bills         netfnIntcOEMGeneral,
156664796041SJason M. Bills         static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
156764796041SJason M. Bills         NULL, ipmiOEMSetSystemGUID,
1568a835eaa0SJia, Chunhui         PRIVILEGE_ADMIN); // set system guid
156964796041SJason M. Bills     ipmiPrintAndRegister(
157064796041SJason M. Bills         netfnIntcOEMGeneral,
157164796041SJason M. Bills         static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
157264796041SJason M. Bills         NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
157364796041SJason M. Bills     ipmiPrintAndRegister(netfnIntcOEMGeneral,
157464796041SJason M. Bills                          static_cast<ipmi_cmd_t>(
157564796041SJason M. Bills                              IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
157664796041SJason M. Bills                          NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
157764796041SJason M. Bills     ipmiPrintAndRegister(
157864796041SJason M. Bills         netfnIntcOEMGeneral,
157964796041SJason M. Bills         static_cast<ipmi_cmd_t>(
158064796041SJason M. Bills             IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
158164796041SJason M. Bills         NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
1582cc49b54bSJia, Chunhui 
1583cc49b54bSJia, Chunhui     ipmi::registerHandler(
1584cc49b54bSJia, Chunhui         ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1585cc49b54bSJia, Chunhui         static_cast<ipmi::Cmd>(
1586cc49b54bSJia, Chunhui             IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
1587cc49b54bSJia, Chunhui         ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
1588cc49b54bSJia, Chunhui 
158964796041SJason M. Bills     ipmiPrintAndRegister(
159064796041SJason M. Bills         netfnIntcOEMGeneral,
159164796041SJason M. Bills         static_cast<ipmi_cmd_t>(
159264796041SJason M. Bills             IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
159364796041SJason M. Bills         NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
159464796041SJason M. Bills     ipmiPrintAndRegister(
159564796041SJason M. Bills         netfnIntcOEMGeneral,
159664796041SJason M. Bills         static_cast<ipmi_cmd_t>(
159764796041SJason M. Bills             IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
159864796041SJason M. Bills         NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
1599d509eb91SSuryakanth Sekar 
1600d509eb91SSuryakanth Sekar     ipmi::registerHandler(
1601d509eb91SSuryakanth Sekar         ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1602d509eb91SSuryakanth Sekar         static_cast<ipmi::Cmd>(
1603d509eb91SSuryakanth Sekar             IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
1604d509eb91SSuryakanth Sekar         ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
1605d509eb91SSuryakanth Sekar 
160664796041SJason M. Bills     ipmiPrintAndRegister(
160764796041SJason M. Bills         netfnIntcOEMGeneral,
160864796041SJason M. Bills         static_cast<ipmi_cmd_t>(
160964796041SJason M. Bills             IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
161064796041SJason M. Bills         NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
161164796041SJason M. Bills     ipmiPrintAndRegister(
161264796041SJason M. Bills         netfnIntcOEMGeneral,
161364796041SJason M. Bills         static_cast<ipmi_cmd_t>(
161464796041SJason M. Bills             IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
161564796041SJason M. Bills         NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
1616703922d0SYong Li     ipmiPrintAndRegister(netfnIntcOEMGeneral,
1617703922d0SYong Li                          static_cast<ipmi_cmd_t>(
1618703922d0SYong Li                              IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
1619703922d0SYong Li                          NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
1620703922d0SYong Li     ipmiPrintAndRegister(netfnIntcOEMGeneral,
1621703922d0SYong Li                          static_cast<ipmi_cmd_t>(
1622703922d0SYong Li                              IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
1623703922d0SYong Li                          NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
162491244a6aSJames Feist 
162591244a6aSJames Feist     ipmiPrintAndRegister(
162691244a6aSJames Feist         netfnIntcOEMGeneral,
162791244a6aSJames Feist         static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
162891244a6aSJames Feist         NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
162991244a6aSJames Feist 
163091244a6aSJames Feist     ipmiPrintAndRegister(
163191244a6aSJames Feist         netfnIntcOEMGeneral,
163291244a6aSJames Feist         static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
163391244a6aSJames Feist         NULL, ipmiOEMGetFanConfig, PRIVILEGE_USER);
163491244a6aSJames Feist 
1635*acc8a4ebSJames Feist     ipmi::registerHandler(
1636*acc8a4ebSJames Feist         ipmi::prioOemBase, netfnIntcOEMGeneral,
1637*acc8a4ebSJames Feist         static_cast<ipmi::Cmd>(
1638*acc8a4ebSJames Feist             IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
1639*acc8a4ebSJames Feist         ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
16405f957cafSJames Feist 
1641*acc8a4ebSJames Feist     ipmi::registerHandler(
1642*acc8a4ebSJames Feist         ipmi::prioOemBase, netfnIntcOEMGeneral,
1643*acc8a4ebSJames Feist         static_cast<ipmi::Cmd>(
1644*acc8a4ebSJames Feist             IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
1645*acc8a4ebSJames Feist         ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
1646*acc8a4ebSJames Feist 
1647*acc8a4ebSJames Feist     ipmi::registerHandler(
1648*acc8a4ebSJames Feist         ipmi::prioOemBase, netfnIntcOEMGeneral,
1649*acc8a4ebSJames Feist         static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
1650*acc8a4ebSJames Feist         ipmi::Privilege::User, ipmiOEMSetFscParameter);
1651*acc8a4ebSJames Feist 
1652*acc8a4ebSJames Feist     ipmi::registerHandler(
1653*acc8a4ebSJames Feist         ipmi::prioOemBase, netfnIntcOEMGeneral,
1654*acc8a4ebSJames Feist         static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
1655*acc8a4ebSJames Feist         ipmi::Privilege::User, ipmiOEMGetFscParameter);
16565f957cafSJames Feist 
165745f04988SKuiying Wang     ipmiPrintAndRegister(
165845f04988SKuiying Wang         netfnIntcOEMGeneral,
165945f04988SKuiying Wang         static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
166045f04988SKuiying Wang         NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
166123737fe3SYong Li     ipmiPrintAndRegister(
166223737fe3SYong Li         netfnIntcOEMPlatform,
166323737fe3SYong Li         static_cast<ipmi_cmd_t>(
166423737fe3SYong Li             IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
166523737fe3SYong Li         NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
1666a835eaa0SJia, Chunhui     return;
1667a835eaa0SJia, Chunhui }
1668a835eaa0SJia, Chunhui 
1669a835eaa0SJia, Chunhui } // namespace ipmi
1670