blob: 0b7c4ef65a5ecee8b1322241774125fc4e563327 [file] [log] [blame]
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Jason M. Bills64796042018-10-03 16:51:55 -070017#include "xyz/openbmc_project/Common/error.hpp"
Kuiying Wang45f04982018-12-26 09:23:08 +080018#include "xyz/openbmc_project/Led/Physical/server.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070019
Jia, Chunhuicc49b542019-03-20 15:41:07 +080020#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080021
22#include <array>
James Feist91244a62019-02-19 15:04:54 -080023#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080024#include <boost/process/child.hpp>
25#include <boost/process/io.hpp>
Chen Yugang39736d52019-07-12 16:24:33 +080026#include <com/intel/Control/NMISource/server.hpp>
Yong Li0669d192019-05-06 14:01:46 +080027#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070028#include <commandutils.hpp>
Vernon Mauery4ac799d2019-05-20 15:50:37 -070029#include <filesystem>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080030#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080031#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070032#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070033#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <phosphor-logging/log.hpp>
36#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053037#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080038#include <string>
James Feist91244a62019-02-19 15:04:54 -080039#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080040#include <vector>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080041#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
42#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080043#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080044
45namespace ipmi
46{
Jason M. Bills64796042018-10-03 16:51:55 -070047static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070048
49namespace netfn::intel
50{
51constexpr NetFn oemGeneral = netFnOemOne;
52constexpr Cmd cmdRestoreConfiguration = 0x02;
53} // namespace netfn::intel
54
Jason M. Bills64796042018-10-03 16:51:55 -070055static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080056
Suryakanth Sekard509eb92018-11-15 17:44:11 +053057static constexpr auto ethernetIntf =
58 "xyz.openbmc_project.Network.EthernetInterface";
59static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
60static constexpr auto networkService = "xyz.openbmc_project.Network";
61static constexpr auto networkRoot = "/xyz/openbmc_project/network";
62
Chen Yugang39736d52019-07-12 16:24:33 +080063static constexpr const char* oemNmiSourceIntf = "com.intel.Control.NMISource";
64static constexpr const char* oemNmiSourceObjPath =
65 "/com/intel/control/NMISource";
66static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
67static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
68
James Feist63efafa2019-07-24 12:39:21 -070069static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
70
Chen Yugang39736d52019-07-12 16:24:33 +080071enum class NmiSource : uint8_t
72{
73 none = 0,
74 fpBtn = 1,
75 wdPreTimeout = 2,
76 pefMatch = 3,
77 chassisCmd = 4,
78 memoryError = 5,
79 pciSerrPerr = 6,
80 southbridgeNmi = 7,
81 chipsetNmi = 8,
82};
83
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080084// return code: 0 successful
85int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
86{
87 std::string objpath = "/xyz/openbmc_project/FruDevice";
88 std::string intf = "xyz.openbmc_project.FruDeviceManager";
89 std::string service = getService(bus, intf, objpath);
90 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
91 if (valueTree.empty())
92 {
93 phosphor::logging::log<phosphor::logging::level::ERR>(
94 "No object implements interface",
95 phosphor::logging::entry("INTF=%s", intf.c_str()));
96 return -1;
97 }
98
Jason M. Bills64796042018-10-03 16:51:55 -070099 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800100 {
101 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
102 if (interface == item.second.end())
103 {
104 continue;
105 }
106
107 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
108 if (property == interface->second.end())
109 {
110 continue;
111 }
112
113 try
114 {
115 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700116 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700117 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800118 {
119 phosphor::logging::log<phosphor::logging::level::ERR>(
120 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800121 return -1;
122 }
Jason M. Bills64796042018-10-03 16:51:55 -0700123 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800124 return 0;
125 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700126 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800127 {
Jason M. Bills64796042018-10-03 16:51:55 -0700128 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800129 return -1;
130 }
131 }
132 return -1;
133}
Jason M. Bills64796042018-10-03 16:51:55 -0700134
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800135ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
136 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700137 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800138{
Jason M. Bills64796042018-10-03 16:51:55 -0700139 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800140 // Status code.
141 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700142 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800143 return rc;
144}
145
146// Returns the Chassis Identifier (serial #)
147ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
148 ipmi_request_t request,
149 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700150 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800151 ipmi_context_t context)
152{
153 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700154 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800155 {
Jason M. Bills64796042018-10-03 16:51:55 -0700156 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800157 return IPMI_CC_REQ_DATA_LEN_INVALID;
158 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700159 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
160 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800161 {
Jason M. Bills64796042018-10-03 16:51:55 -0700162 *dataLen = serial.size(); // length will never exceed response length
163 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800164 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700165 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800166 return IPMI_CC_OK;
167 }
Jason M. Bills64796042018-10-03 16:51:55 -0700168 *dataLen = 0;
169 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800170}
171
172ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
173 ipmi_request_t request,
174 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700175 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800176{
177 static constexpr size_t safeBufferLength = 50;
178 char buf[safeBufferLength] = {0};
179 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
180
Jason M. Bills64796042018-10-03 16:51:55 -0700181 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800182 {
Jason M. Bills64796042018-10-03 16:51:55 -0700183 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800184 return IPMI_CC_REQ_DATA_LEN_INVALID;
185 }
186
Jason M. Bills64796042018-10-03 16:51:55 -0700187 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800188
189 snprintf(
190 buf, safeBufferLength,
191 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
192 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
193 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
194 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
195 Data->node3, Data->node2, Data->node1);
196 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
197 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800198
199 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
200 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700201 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
202 std::string service = getService(*dbus, intf, objpath);
203 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800204 return IPMI_CC_OK;
205}
206
Jason M. Billsb02bf092019-08-15 13:01:56 -0700207ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
208 uint7_t reserved1)
209{
210 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
211
212 try
213 {
214 auto service =
215 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
216 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
217 bmcResetDisablesIntf, "ResetOnSMI",
218 !disableResetOnSMI);
219 }
220 catch (std::exception& e)
221 {
222 phosphor::logging::log<phosphor::logging::level::ERR>(
223 "Failed to set BMC reset disables",
224 phosphor::logging::entry("EXCEPTION=%s", e.what()));
225 return ipmi::responseUnspecifiedError();
226 }
227
228 return ipmi::responseSuccess();
229}
230
231ipmi::RspType<bool, // disableResetOnSMI
232 uint7_t // reserved
233 >
234 ipmiOEMGetBMCResetDisables()
235{
236 bool disableResetOnSMI = true;
237
238 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
239 try
240 {
241 auto service =
242 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
243 Value variant =
244 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
245 bmcResetDisablesIntf, "ResetOnSMI");
246 disableResetOnSMI = !std::get<bool>(variant);
247 }
248 catch (std::exception& e)
249 {
250 phosphor::logging::log<phosphor::logging::level::ERR>(
251 "Failed to get BMC reset disables",
252 phosphor::logging::entry("EXCEPTION=%s", e.what()));
253 return ipmi::responseUnspecifiedError();
254 }
255
256 return ipmi::responseSuccess(disableResetOnSMI, 0);
257}
258
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800259ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
260 ipmi_request_t request, ipmi_response_t response,
261 ipmi_data_len_t dataLen, ipmi_context_t context)
262{
263 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
264
Jason M. Bills64796042018-10-03 16:51:55 -0700265 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800266 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800267 *dataLen = 0;
268 return IPMI_CC_REQ_DATA_LEN_INVALID;
269 }
Jason M. Bills64796042018-10-03 16:51:55 -0700270 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800271
Vernon Mauery15419dd2019-05-24 09:40:30 -0700272 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
273 std::string service = getService(*dbus, biosIntf, biosObjPath);
274 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800275 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
276 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700277 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800278 *dataLen = 1;
279 return IPMI_CC_OK;
280}
281
282ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
283 ipmi_request_t request,
284 ipmi_response_t response,
285 ipmi_data_len_t dataLen, ipmi_context_t context)
286{
287 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
288 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
289
290 if (*dataLen == 0)
291 {
Jason M. Bills64796042018-10-03 16:51:55 -0700292 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 return IPMI_CC_REQ_DATA_LEN_INVALID;
294 }
295
296 size_t reqDataLen = *dataLen;
297 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700298 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800299 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800300 return IPMI_CC_INVALID_FIELD_REQUEST;
301 }
302
303 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700304 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800305 {
306 case OEMDevEntityType::biosId:
307 {
308 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
309 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800310 return IPMI_CC_REQ_DATA_LEN_INVALID;
311 }
312
Vernon Mauery15419dd2019-05-24 09:40:30 -0700313 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
314 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 try
316 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700317 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800318 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700319 std::string& idString = std::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800320 if (req->offset >= idString.size())
321 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800322 return IPMI_CC_PARM_OUT_OF_RANGE;
323 }
Jason M. Bills64796042018-10-03 16:51:55 -0700324 size_t length = 0;
325 if (req->countToRead > (idString.size() - req->offset))
326 {
327 length = idString.size() - req->offset;
328 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800329 else
330 {
Jason M. Bills64796042018-10-03 16:51:55 -0700331 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800332 }
Jason M. Bills64796042018-10-03 16:51:55 -0700333 std::copy(idString.begin() + req->offset, idString.end(),
334 res->data);
335 res->resDatalen = length;
336 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800337 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700338 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800339 {
Jason M. Bills64796042018-10-03 16:51:55 -0700340 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800341 return IPMI_CC_UNSPECIFIED_ERROR;
342 }
343 }
344 break;
345
346 case OEMDevEntityType::devVer:
347 case OEMDevEntityType::sdrVer:
348 // TODO:
349 return IPMI_CC_ILLEGAL_COMMAND;
350 default:
351 return IPMI_CC_INVALID_FIELD_REQUEST;
352 }
353 return IPMI_CC_OK;
354}
355
356ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
357 ipmi_request_t request, ipmi_response_t response,
358 ipmi_data_len_t dataLen, ipmi_context_t context)
359{
360 if (*dataLen != 0)
361 {
Jason M. Bills64796042018-10-03 16:51:55 -0700362 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800363 return IPMI_CC_REQ_DATA_LEN_INVALID;
364 }
365
366 *dataLen = 1;
367 uint8_t* res = reinterpret_cast<uint8_t*>(response);
368 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
369 // AIC is available so that BIOS will not timeout repeatly which leads to
370 // slow booting.
371 *res = 0; // Byte1=Count of SlotPosition/FruID records.
372 return IPMI_CC_OK;
373}
374
Jason M. Bills64796042018-10-03 16:51:55 -0700375ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
376 ipmi_request_t request,
377 ipmi_response_t response,
378 ipmi_data_len_t dataLen,
379 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800380{
Jason M. Bills64796042018-10-03 16:51:55 -0700381 GetPowerRestoreDelayRes* resp =
382 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
383
384 if (*dataLen != 0)
385 {
386 *dataLen = 0;
387 return IPMI_CC_REQ_DATA_LEN_INVALID;
388 }
389
Vernon Mauery15419dd2019-05-24 09:40:30 -0700390 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700391 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700392 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700393 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700394 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700395 powerRestoreDelayIntf, powerRestoreDelayProp);
396
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700397 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700398 resp->byteLSB = delay;
399 resp->byteMSB = delay >> 8;
400
401 *dataLen = sizeof(GetPowerRestoreDelayRes);
402
403 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800404}
405
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800406static uint8_t bcdToDec(uint8_t val)
407{
408 return ((val / 16 * 10) + (val % 16));
409}
410
411// Allows an update utility or system BIOS to send the status of an embedded
412// firmware update attempt to the BMC. After received, BMC will create a logging
413// record.
414ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
415 uint8_t majorRevision,
416 uint8_t minorRevision,
417 uint32_t auxInfo)
418{
419 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700420 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800421 target = (target & selEvtTargetMask) >> selEvtTargetShift;
422
423 /* make sure the status is 0, 1, or 2 as per the spec */
424 if (status > 2)
425 {
426 return ipmi::response(ipmi::ccInvalidFieldRequest);
427 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700428 /* make sure the target is 0, 1, 2, or 4 as per the spec */
429 if (target > 4 || target == 3)
430 {
431 return ipmi::response(ipmi::ccInvalidFieldRequest);
432 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800433 /*orignal OEM command is to record OEM SEL.
434 But openbmc does not support OEM SEL, so we redirect it to redfish event
435 logging. */
436 std::string buildInfo;
437 std::string action;
438 switch (FWUpdateTarget(target))
439 {
440 case FWUpdateTarget::targetBMC:
441 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700442 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800443 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
444 " BuildID: " + std::to_string(auxInfo);
445 buildInfo += std::to_string(auxInfo);
446 break;
447 case FWUpdateTarget::targetBIOS:
448 firmware = "BIOS";
449 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700450 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800451 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
452 " minor: " +
453 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
454 " ReleaseNumber: " + // ASCII encoded
455 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
456 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
457 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
458 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
459 break;
460 case FWUpdateTarget::targetME:
461 firmware = "ME";
462 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700463 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800464 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
465 " minor2: " +
466 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
467 " build1: " +
468 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
469 " build2: " +
470 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
471 break;
472 case FWUpdateTarget::targetOEMEWS:
473 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700474 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800475 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
476 " BuildID: " + std::to_string(auxInfo);
477 break;
478 }
479
Jason M. Billsdc249272019-04-03 09:58:40 -0700480 static const std::string openBMCMessageRegistryVersion("0.1");
481 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
482
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800483 switch (status)
484 {
485 case 0x0:
486 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700487 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800488 break;
489 case 0x1:
490 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700491 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800492 break;
493 case 0x2:
494 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700495 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800496 break;
497 default:
498 action = "unknown";
499 break;
500 }
501
Jason M. Billsdc249272019-04-03 09:58:40 -0700502 std::string firmwareInstanceStr =
503 firmware + " instance: " + std::to_string(instance);
504 std::string message("[firmware update] " + firmwareInstanceStr +
505 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800506
507 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700508 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
509 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
510 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800511 return ipmi::responseSuccess();
512}
513
Jason M. Bills64796042018-10-03 16:51:55 -0700514ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
515 ipmi_request_t request,
516 ipmi_response_t response,
517 ipmi_data_len_t dataLen,
518 ipmi_context_t context)
519{
520 SetPowerRestoreDelayReq* data =
521 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
522 uint16_t delay = 0;
523
524 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
525 {
526 *dataLen = 0;
527 return IPMI_CC_REQ_DATA_LEN_INVALID;
528 }
529 delay = data->byteMSB;
530 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700531 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700532 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700533 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
534 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700535 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
536 *dataLen = 0;
537
538 return IPMI_CC_OK;
539}
540
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700541static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700542{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700543 static constexpr const char* cpuPresencePathPrefix =
544 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
545 static constexpr const char* cpuPresenceIntf =
546 "xyz.openbmc_project.Inventory.Item";
547 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
548 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
549 try
Jason M. Bills64796042018-10-03 16:51:55 -0700550 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700551 auto service =
552 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
553
554 ipmi::Value result = ipmi::getDbusProperty(
555 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
556 return std::get<bool>(result);
557 }
558 catch (const std::exception& e)
559 {
560 phosphor::logging::log<phosphor::logging::level::INFO>(
561 "Cannot find processor presence",
562 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
563 return false;
564 }
565}
566
567ipmi::RspType<bool, // CATERR Reset Enabled
568 bool, // ERR2 Reset Enabled
569 uint6_t, // reserved
570 uint8_t, // reserved, returns 0x3F
571 uint6_t, // CPU1 CATERR Count
572 uint2_t, // CPU1 Status
573 uint6_t, // CPU2 CATERR Count
574 uint2_t, // CPU2 Status
575 uint6_t, // CPU3 CATERR Count
576 uint2_t, // CPU3 Status
577 uint6_t, // CPU4 CATERR Count
578 uint2_t, // CPU4 Status
579 uint8_t // Crashdump Count
580 >
581 ipmiOEMGetProcessorErrConfig()
582{
583 bool resetOnCATERR = false;
584 bool resetOnERR2 = false;
585 uint6_t cpu1CATERRCount = 0;
586 uint6_t cpu2CATERRCount = 0;
587 uint6_t cpu3CATERRCount = 0;
588 uint6_t cpu4CATERRCount = 0;
589 uint8_t crashdumpCount = 0;
590 uint2_t cpu1Status =
591 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
592 uint2_t cpu2Status =
593 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
594 uint2_t cpu3Status =
595 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
596 uint2_t cpu4Status =
597 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
598
599 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
600 try
601 {
602 auto service = ipmi::getService(*busp, processorErrConfigIntf,
603 processorErrConfigObjPath);
604
605 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
606 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
607 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
608 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
609 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
610 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
611 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
612 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
613 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
614 }
615 catch (const std::exception& e)
616 {
617 phosphor::logging::log<phosphor::logging::level::ERR>(
618 "Failed to fetch processor error config",
619 phosphor::logging::entry("ERROR=%s", e.what()));
620 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700621 }
622
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700623 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
624 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
625 cpu2Status, cpu3CATERRCount, cpu3Status,
626 cpu4CATERRCount, cpu4Status, crashdumpCount);
627}
Jason M. Bills64796042018-10-03 16:51:55 -0700628
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700629ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
630 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
631 std::optional<bool> clearCPUErrorCount,
632 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
633{
634 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700635
636 try
637 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700638 auto service = ipmi::getService(*busp, processorErrConfigIntf,
639 processorErrConfigObjPath);
640 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
641 processorErrConfigIntf, "ResetOnCATERR",
642 resetOnCATERR);
643 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
644 processorErrConfigIntf, "ResetOnERR2",
645 resetOnERR2);
646 if (clearCPUErrorCount.value_or(false))
647 {
648 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700649 processorErrConfigIntf, "ErrorCountCPU1",
650 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700651 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700652 processorErrConfigIntf, "ErrorCountCPU2",
653 static_cast<uint8_t>(0));
654 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
655 processorErrConfigIntf, "ErrorCountCPU3",
656 static_cast<uint8_t>(0));
657 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
658 processorErrConfigIntf, "ErrorCountCPU4",
659 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700660 }
661 if (clearCrashdumpCount.value_or(false))
662 {
663 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700664 processorErrConfigIntf, "CrashdumpCount",
665 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700666 }
Jason M. Bills64796042018-10-03 16:51:55 -0700667 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700668 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700669 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800670 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700671 "Failed to set processor error config",
672 phosphor::logging::entry("EXCEPTION=%s", e.what()));
673 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700674 }
675
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700676 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700677}
678
Yong Li703922d2018-11-06 13:25:31 +0800679ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
680 ipmi_request_t request,
681 ipmi_response_t response,
682 ipmi_data_len_t dataLen,
683 ipmi_context_t context)
684{
685 GetOEMShutdownPolicyRes* resp =
686 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
687
688 if (*dataLen != 0)
689 {
690 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800691 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800692 *dataLen = 0;
693 return IPMI_CC_REQ_DATA_LEN_INVALID;
694 }
695
696 *dataLen = 0;
697
698 try
699 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700700 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800701 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700702 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
703 Value variant = getDbusProperty(
704 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
705 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800706
707 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
708 convertPolicyFromString(std::get<std::string>(variant)) ==
709 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
710 NoShutdownOnOCOT)
711 {
712 resp->policy = 0;
713 }
714 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
715 convertPolicyFromString(std::get<std::string>(variant)) ==
716 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
717 Policy::ShutdownOnOCOT)
718 {
719 resp->policy = 1;
720 }
721 else
722 {
723 phosphor::logging::log<phosphor::logging::level::ERR>(
724 "oem_set_shutdown_policy: invalid property!",
725 phosphor::logging::entry(
726 "PROP=%s", std::get<std::string>(variant).c_str()));
727 return IPMI_CC_UNSPECIFIED_ERROR;
728 }
Yong Li703922d2018-11-06 13:25:31 +0800729 // TODO needs to check if it is multi-node products,
730 // policy is only supported on node 3/4
731 resp->policySupport = shutdownPolicySupported;
732 }
733 catch (sdbusplus::exception_t& e)
734 {
735 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
736 return IPMI_CC_UNSPECIFIED_ERROR;
737 }
738
739 *dataLen = sizeof(GetOEMShutdownPolicyRes);
740 return IPMI_CC_OK;
741}
742
743ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
744 ipmi_request_t request,
745 ipmi_response_t response,
746 ipmi_data_len_t dataLen,
747 ipmi_context_t context)
748{
749 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800750 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
751 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
752 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800753
754 // TODO needs to check if it is multi-node products,
755 // policy is only supported on node 3/4
756 if (*dataLen != 1)
757 {
758 phosphor::logging::log<phosphor::logging::level::ERR>(
759 "oem_set_shutdown_policy: invalid input len!");
760 *dataLen = 0;
761 return IPMI_CC_REQ_DATA_LEN_INVALID;
762 }
763
764 *dataLen = 0;
765 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
766 {
767 phosphor::logging::log<phosphor::logging::level::ERR>(
768 "oem_set_shutdown_policy: invalid input!");
769 return IPMI_CC_INVALID_FIELD_REQUEST;
770 }
771
Yong Li0669d192019-05-06 14:01:46 +0800772 if (*req == noShutdownOnOCOT)
773 {
774 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
775 Policy::NoShutdownOnOCOT;
776 }
777 else
778 {
779 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
780 Policy::ShutdownOnOCOT;
781 }
782
Yong Li703922d2018-11-06 13:25:31 +0800783 try
784 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700785 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800786 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700787 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800788 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700789 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800790 oemShutdownPolicyObjPathProp,
791 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800792 }
793 catch (sdbusplus::exception_t& e)
794 {
795 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
796 return IPMI_CC_UNSPECIFIED_ERROR;
797 }
798
799 return IPMI_CC_OK;
800}
801
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530802/** @brief implementation for check the DHCP or not in IPv4
803 * @param[in] Channel - Channel number
804 * @returns true or false.
805 */
806static bool isDHCPEnabled(uint8_t Channel)
807{
808 try
809 {
810 auto ethdevice = getChannelName(Channel);
811 if (ethdevice.empty())
812 {
813 return false;
814 }
815 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700816 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530817 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700818 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
819 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530820 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700821 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530822 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
823 {
824 return true;
825 }
826 else
827 {
828 return false;
829 }
830 }
831 catch (sdbusplus::exception_t& e)
832 {
833 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
834 return true;
835 }
836}
837
838/** @brief implementes for check the DHCP or not in IPv6
839 * @param[in] Channel - Channel number
840 * @returns true or false.
841 */
842static bool isDHCPIPv6Enabled(uint8_t Channel)
843{
844
845 try
846 {
847 auto ethdevice = getChannelName(Channel);
848 if (ethdevice.empty())
849 {
850 return false;
851 }
852 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700853 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530854 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700855 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
856 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530857 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700858 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530859 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
860 {
861 return true;
862 }
863 else
864 {
865 return false;
866 }
867 }
868 catch (sdbusplus::exception_t& e)
869 {
870 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
871 return true;
872 }
873}
874
875/** @brief implementes the creating of default new user
876 * @param[in] userName - new username in 16 bytes.
877 * @param[in] userPassword - new password in 20 bytes
878 * @returns ipmi completion code.
879 */
880ipmi::RspType<> ipmiOEMSetUser2Activation(
881 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
882 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
883{
884 bool userState = false;
885 // Check for System Interface not exist and LAN should be static
886 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
887 {
888 ChannelInfo chInfo;
889 try
890 {
891 getChannelInfo(channel, chInfo);
892 }
893 catch (sdbusplus::exception_t& e)
894 {
895 phosphor::logging::log<phosphor::logging::level::ERR>(
896 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
897 phosphor::logging::entry("MSG: %s", e.description()));
898 return ipmi::response(ipmi::ccUnspecifiedError);
899 }
900 if (chInfo.mediumType ==
901 static_cast<uint8_t>(EChannelMediumType::systemInterface))
902 {
903 phosphor::logging::log<phosphor::logging::level::ERR>(
904 "ipmiOEMSetUser2Activation: system interface exist .");
905 return ipmi::response(ipmi::ccCommandNotAvailable);
906 }
907 else
908 {
909
910 if (chInfo.mediumType ==
911 static_cast<uint8_t>(EChannelMediumType::lan8032))
912 {
913 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
914 {
915 phosphor::logging::log<phosphor::logging::level::ERR>(
916 "ipmiOEMSetUser2Activation: DHCP enabled .");
917 return ipmi::response(ipmi::ccCommandNotAvailable);
918 }
919 }
920 }
921 }
922 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
923 if (ipmi::ccSuccess ==
924 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
925 {
926 if (enabledUsers > 1)
927 {
928 phosphor::logging::log<phosphor::logging::level::ERR>(
929 "ipmiOEMSetUser2Activation: more than one user is enabled.");
930 return ipmi::response(ipmi::ccCommandNotAvailable);
931 }
932 // Check the user 2 is enabled or not
933 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
934 if (userState == true)
935 {
936 phosphor::logging::log<phosphor::logging::level::ERR>(
937 "ipmiOEMSetUser2Activation: user 2 already enabled .");
938 return ipmi::response(ipmi::ccCommandNotAvailable);
939 }
940 }
941 else
942 {
943 return ipmi::response(ipmi::ccUnspecifiedError);
944 }
945
946#if BYTE_ORDER == LITTLE_ENDIAN
947 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
948#endif
949#if BYTE_ORDER == BIG_ENDIAN
950 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
951#endif
952
953 if (ipmi::ccSuccess ==
954 ipmiUserSetUserName(ipmiDefaultUserId,
955 reinterpret_cast<const char*>(userName.data())))
956 {
957 if (ipmi::ccSuccess ==
958 ipmiUserSetUserPassword(
959 ipmiDefaultUserId,
960 reinterpret_cast<const char*>(userPassword.data())))
961 {
962 if (ipmi::ccSuccess ==
963 ipmiUserSetPrivilegeAccess(
964 ipmiDefaultUserId,
965 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
966 privAccess, true))
967 {
968 phosphor::logging::log<phosphor::logging::level::INFO>(
969 "ipmiOEMSetUser2Activation: user created successfully ");
970 return ipmi::responseSuccess();
971 }
972 }
973 // we need to delete the default user id which added in this command as
974 // password / priv setting is failed.
975 ipmiUserSetUserName(ipmiDefaultUserId, "");
976 phosphor::logging::log<phosphor::logging::level::ERR>(
977 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
978 }
979 else
980 {
981 phosphor::logging::log<phosphor::logging::level::ERR>(
982 "ipmiOEMSetUser2Activation: Setting username failed.");
983 }
984
985 return ipmi::response(ipmi::ccCommandNotAvailable);
986}
987
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +0530988/** @brief implementes setting password for special user
989 * @param[in] specialUserIndex
990 * @param[in] userPassword - new password in 20 bytes
991 * @returns ipmi completion code.
992 */
993ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
994 uint8_t specialUserIndex,
995 std::vector<uint8_t> userPassword)
996{
997 ChannelInfo chInfo;
998 try
999 {
1000 getChannelInfo(ctx->channel, chInfo);
1001 }
1002 catch (sdbusplus::exception_t& e)
1003 {
1004 phosphor::logging::log<phosphor::logging::level::ERR>(
1005 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1006 phosphor::logging::entry("MSG: %s", e.description()));
1007 return ipmi::responseUnspecifiedError();
1008 }
1009 if (chInfo.mediumType !=
1010 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1011 {
1012 phosphor::logging::log<phosphor::logging::level::ERR>(
1013 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1014 "interface");
1015 return ipmi::responseCommandNotAvailable();
1016 }
1017 if (specialUserIndex != 0)
1018 {
1019 phosphor::logging::log<phosphor::logging::level::ERR>(
1020 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1021 return ipmi::responseParmOutOfRange();
1022 }
1023 constexpr uint8_t minPasswordSizeRequired = 6;
1024 if (userPassword.size() < minPasswordSizeRequired ||
1025 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1026 {
1027 return ipmi::responseReqDataLenInvalid();
1028 }
1029 std::string passwd;
1030 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1031 userPassword.size());
1032 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
1033}
1034
Kuiying Wang45f04982018-12-26 09:23:08 +08001035namespace ledAction
1036{
1037using namespace sdbusplus::xyz::openbmc_project::Led::server;
1038std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
1039 {Physical::Action::Off, 0x00},
1040 {Physical::Action::On, 0x10},
1041 {Physical::Action::Blink, 0x01}};
1042
1043std::map<uint8_t, std::string> offsetObjPath = {
1044 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1045
1046} // namespace ledAction
1047
1048int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1049 const std::string& objPath, uint8_t& state)
1050{
1051 try
1052 {
1053 std::string service = getService(bus, intf, objPath);
1054 Value stateValue =
1055 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001056 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001057 state = ledAction::actionDbusToIpmi.at(
1058 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1059 convertActionFromString(strState));
1060 }
1061 catch (sdbusplus::exception::SdBusError& e)
1062 {
1063 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1064 return -1;
1065 }
1066 return 0;
1067}
1068
1069ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1070 ipmi_request_t request, ipmi_response_t response,
1071 ipmi_data_len_t dataLen, ipmi_context_t context)
1072{
1073 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1074 // LED Status
1075 //[1:0] = Reserved
1076 //[3:2] = Status(Amber)
1077 //[5:4] = Status(Green)
1078 //[7:6] = System Identify
1079 // Status definitions:
1080 // 00b = Off
1081 // 01b = Blink
1082 // 10b = On
1083 // 11b = invalid
1084 if (*dataLen != 0)
1085 {
1086 phosphor::logging::log<phosphor::logging::level::ERR>(
1087 "oem_get_led_status: invalid input len!");
1088 *dataLen = 0;
1089 return IPMI_CC_REQ_DATA_LEN_INVALID;
1090 }
1091
1092 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1093 *resp = 0;
1094 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001095 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001096 for (auto it = ledAction::offsetObjPath.begin();
1097 it != ledAction::offsetObjPath.end(); ++it)
1098 {
1099 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001100 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001101 {
1102 phosphor::logging::log<phosphor::logging::level::ERR>(
1103 "oem_get_led_status: fail to get ID LED status!");
1104 return IPMI_CC_UNSPECIFIED_ERROR;
1105 }
1106 *resp |= state << it->first;
1107 }
1108
1109 *dataLen = sizeof(*resp);
1110 return IPMI_CC_OK;
1111}
1112
Yong Li23737fe2019-02-19 08:49:55 +08001113ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1114 ipmi_request_t request,
1115 ipmi_response_t response,
1116 ipmi_data_len_t dataLen,
1117 ipmi_context_t context)
1118{
1119 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1120 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1121
1122 if (*dataLen == 0)
1123 {
1124 phosphor::logging::log<phosphor::logging::level::ERR>(
1125 "CfgHostSerial: invalid input len!",
1126 phosphor::logging::entry("LEN=%d", *dataLen));
1127 return IPMI_CC_REQ_DATA_LEN_INVALID;
1128 }
1129
1130 switch (req->command)
1131 {
1132 case getHostSerialCfgCmd:
1133 {
1134 if (*dataLen != 1)
1135 {
1136 phosphor::logging::log<phosphor::logging::level::ERR>(
1137 "CfgHostSerial: invalid input len!");
1138 *dataLen = 0;
1139 return IPMI_CC_REQ_DATA_LEN_INVALID;
1140 }
1141
1142 *dataLen = 0;
1143
1144 boost::process::ipstream is;
1145 std::vector<std::string> data;
1146 std::string line;
1147 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1148 boost::process::std_out > is);
1149
1150 while (c1.running() && std::getline(is, line) && !line.empty())
1151 {
1152 data.push_back(line);
1153 }
1154
1155 c1.wait();
1156 if (c1.exit_code())
1157 {
1158 phosphor::logging::log<phosphor::logging::level::ERR>(
1159 "CfgHostSerial:: error on execute",
1160 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1161 // Using the default value
1162 *resp = 0;
1163 }
1164 else
1165 {
1166 if (data.size() != 1)
1167 {
1168 phosphor::logging::log<phosphor::logging::level::ERR>(
1169 "CfgHostSerial:: error on read env");
1170 return IPMI_CC_UNSPECIFIED_ERROR;
1171 }
1172 try
1173 {
1174 unsigned long tmp = std::stoul(data[0]);
1175 if (tmp > std::numeric_limits<uint8_t>::max())
1176 {
1177 throw std::out_of_range("Out of range");
1178 }
1179 *resp = static_cast<uint8_t>(tmp);
1180 }
1181 catch (const std::invalid_argument& e)
1182 {
1183 phosphor::logging::log<phosphor::logging::level::ERR>(
1184 "invalid config ",
1185 phosphor::logging::entry("ERR=%s", e.what()));
1186 return IPMI_CC_UNSPECIFIED_ERROR;
1187 }
1188 catch (const std::out_of_range& e)
1189 {
1190 phosphor::logging::log<phosphor::logging::level::ERR>(
1191 "out_of_range config ",
1192 phosphor::logging::entry("ERR=%s", e.what()));
1193 return IPMI_CC_UNSPECIFIED_ERROR;
1194 }
1195 }
1196
1197 *dataLen = 1;
1198 break;
1199 }
1200 case setHostSerialCfgCmd:
1201 {
1202 if (*dataLen != sizeof(CfgHostSerialReq))
1203 {
1204 phosphor::logging::log<phosphor::logging::level::ERR>(
1205 "CfgHostSerial: invalid input len!");
1206 *dataLen = 0;
1207 return IPMI_CC_REQ_DATA_LEN_INVALID;
1208 }
1209
1210 *dataLen = 0;
1211
1212 if (req->parameter > HostSerialCfgParamMax)
1213 {
1214 phosphor::logging::log<phosphor::logging::level::ERR>(
1215 "CfgHostSerial: invalid input!");
1216 return IPMI_CC_INVALID_FIELD_REQUEST;
1217 }
1218
1219 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1220 std::to_string(req->parameter));
1221
1222 c1.wait();
1223 if (c1.exit_code())
1224 {
1225 phosphor::logging::log<phosphor::logging::level::ERR>(
1226 "CfgHostSerial:: error on execute",
1227 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1228 return IPMI_CC_UNSPECIFIED_ERROR;
1229 }
1230 break;
1231 }
1232 default:
1233 phosphor::logging::log<phosphor::logging::level::ERR>(
1234 "CfgHostSerial: invalid input!");
1235 *dataLen = 0;
1236 return IPMI_CC_INVALID_FIELD_REQUEST;
1237 }
1238
1239 return IPMI_CC_OK;
1240}
1241
James Feist91244a62019-02-19 15:04:54 -08001242constexpr const char* thermalModeInterface =
1243 "xyz.openbmc_project.Control.ThermalMode";
1244constexpr const char* thermalModePath =
1245 "/xyz/openbmc_project/control/thermal_mode";
1246
1247bool getFanProfileInterface(
1248 sdbusplus::bus::bus& bus,
1249 boost::container::flat_map<
1250 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1251{
1252 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1253 "GetAll");
1254 call.append(thermalModeInterface);
1255 try
1256 {
1257 auto data = bus.call(call);
1258 data.read(resp);
1259 }
1260 catch (sdbusplus::exception_t& e)
1261 {
1262 phosphor::logging::log<phosphor::logging::level::ERR>(
1263 "getFanProfileInterface: can't get thermal mode!",
1264 phosphor::logging::entry("ERR=%s", e.what()));
1265 return false;
1266 }
1267 return true;
1268}
1269
1270ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1271 ipmi_request_t request, ipmi_response_t response,
1272 ipmi_data_len_t dataLen, ipmi_context_t context)
1273{
1274
1275 if (*dataLen < 2 || *dataLen > 7)
1276 {
1277 phosphor::logging::log<phosphor::logging::level::ERR>(
1278 "ipmiOEMSetFanConfig: invalid input len!");
1279 *dataLen = 0;
1280 return IPMI_CC_REQ_DATA_LEN_INVALID;
1281 }
1282
1283 // todo: tell bios to only send first 2 bytes
1284
1285 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1286 boost::container::flat_map<
1287 std::string, std::variant<std::vector<std::string>, std::string>>
1288 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001289 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1290 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001291 {
1292 return IPMI_CC_UNSPECIFIED_ERROR;
1293 }
1294
1295 std::vector<std::string>* supported =
1296 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1297 if (supported == nullptr)
1298 {
1299 return IPMI_CC_INVALID_FIELD_REQUEST;
1300 }
1301 std::string mode;
1302 if (req->flags &
1303 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1304 {
1305 bool performanceMode =
1306 (req->flags & (1 << static_cast<uint8_t>(
1307 setFanProfileFlags::performAcousSelect))) > 0;
1308
1309 if (performanceMode)
1310 {
1311
1312 if (std::find(supported->begin(), supported->end(),
1313 "Performance") != supported->end())
1314 {
1315 mode = "Performance";
1316 }
1317 }
1318 else
1319 {
1320
1321 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1322 supported->end())
1323 {
1324 mode = "Acoustic";
1325 }
1326 }
1327 if (mode.empty())
1328 {
1329 return IPMI_CC_INVALID_FIELD_REQUEST;
1330 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001331 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001332 thermalModeInterface, "Current", mode);
1333 }
1334
1335 return IPMI_CC_OK;
1336}
1337
James Feist5b693632019-07-09 09:06:09 -07001338ipmi::RspType<uint8_t, // profile support map
1339 uint8_t, // fan control profile enable
1340 uint8_t, // flags
1341 uint32_t // dimm presence bit map
1342 >
1343 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001344{
James Feist91244a62019-02-19 15:04:54 -08001345 boost::container::flat_map<
1346 std::string, std::variant<std::vector<std::string>, std::string>>
1347 profileData;
1348
Vernon Mauery15419dd2019-05-24 09:40:30 -07001349 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1350 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001351 {
James Feist5b693632019-07-09 09:06:09 -07001352 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001353 }
1354
1355 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1356
1357 if (current == nullptr)
1358 {
1359 phosphor::logging::log<phosphor::logging::level::ERR>(
1360 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001361 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001362 }
1363 bool performance = (*current == "Performance");
1364
James Feist5b693632019-07-09 09:06:09 -07001365 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001366 if (performance)
1367 {
James Feist5b693632019-07-09 09:06:09 -07001368 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001369 }
1370
James Feist5b693632019-07-09 09:06:09 -07001371 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001372}
James Feist5f957ca2019-03-14 15:33:55 -07001373constexpr const char* cfmLimitSettingPath =
1374 "/xyz/openbmc_project/control/cfm_limit";
1375constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001376constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001377constexpr const size_t legacyPCHSensorNumber = 0x22;
1378constexpr const char* exitAirPathName = "Exit_Air";
1379constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001380constexpr const char* pidConfigurationIface =
1381 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001382
James Feist09f6b602019-08-08 11:30:03 -07001383static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001384{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001385 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001386 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001387 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1388 "/xyz/openbmc_project/object_mapper",
1389 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001390
James Feistacc8a4e2019-04-02 14:23:57 -07001391 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001392 std::string path;
1393 GetSubTreeType resp;
1394 try
1395 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001396 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001397 reply.read(resp);
1398 }
1399 catch (sdbusplus::exception_t&)
1400 {
1401 phosphor::logging::log<phosphor::logging::level::ERR>(
1402 "ipmiOEMGetFscParameter: mapper error");
1403 };
James Feist09f6b602019-08-08 11:30:03 -07001404 auto config =
1405 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1406 return pair.first.find(name) != std::string::npos;
1407 });
James Feistfaa4f222019-03-21 16:21:55 -07001408 if (config != resp.end())
1409 {
1410 path = std::move(config->first);
1411 }
1412 return path;
1413}
James Feist5f957ca2019-03-14 15:33:55 -07001414
James Feistacc8a4e2019-04-02 14:23:57 -07001415// flat map to make alphabetical
1416static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1417{
1418 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001419 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001420 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001421 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1422 "/xyz/openbmc_project/object_mapper",
1423 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001424
1425 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1426 GetSubTreeType resp;
1427
1428 try
1429 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001430 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001431 reply.read(resp);
1432 }
1433 catch (sdbusplus::exception_t&)
1434 {
1435 phosphor::logging::log<phosphor::logging::level::ERR>(
1436 "getFanConfigPaths: mapper error");
1437 };
1438 for (const auto& [path, objects] : resp)
1439 {
1440 if (objects.empty())
1441 {
1442 continue; // should be impossible
1443 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001444
1445 try
1446 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001447 ret.emplace(path,
1448 getAllDbusProperties(*dbus, objects[0].first, path,
1449 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001450 }
1451 catch (sdbusplus::exception_t& e)
1452 {
1453 phosphor::logging::log<phosphor::logging::level::ERR>(
1454 "getPidConfigs: can't get DbusProperties!",
1455 phosphor::logging::entry("ERR=%s", e.what()));
1456 }
James Feistacc8a4e2019-04-02 14:23:57 -07001457 }
1458 return ret;
1459}
1460
1461ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1462{
1463 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1464 if (data.empty())
1465 {
1466 return ipmi::responseResponseError();
1467 }
1468 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1469 for (const auto& [_, pid] : data)
1470 {
1471 auto findClass = pid.find("Class");
1472 if (findClass == pid.end())
1473 {
1474 phosphor::logging::log<phosphor::logging::level::ERR>(
1475 "ipmiOEMGetFscParameter: found illegal pid "
1476 "configurations");
1477 return ipmi::responseResponseError();
1478 }
1479 std::string type = std::get<std::string>(findClass->second);
1480 if (type == "fan")
1481 {
1482 auto findOutLimit = pid.find("OutLimitMin");
1483 if (findOutLimit == pid.end())
1484 {
1485 phosphor::logging::log<phosphor::logging::level::ERR>(
1486 "ipmiOEMGetFscParameter: found illegal pid "
1487 "configurations");
1488 return ipmi::responseResponseError();
1489 }
1490 // get the min out of all the offsets
1491 minOffset = std::min(
1492 minOffset,
1493 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1494 }
1495 }
1496 if (minOffset == std::numeric_limits<uint8_t>::max())
1497 {
1498 phosphor::logging::log<phosphor::logging::level::ERR>(
1499 "ipmiOEMGetFscParameter: found no fan configurations!");
1500 return ipmi::responseResponseError();
1501 }
1502
1503 return ipmi::responseSuccess(minOffset);
1504}
1505
1506ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1507{
1508 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1509 if (data.empty())
1510 {
1511
1512 phosphor::logging::log<phosphor::logging::level::ERR>(
1513 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1514 return ipmi::responseResponseError();
1515 }
1516
Vernon Mauery15419dd2019-05-24 09:40:30 -07001517 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001518 bool found = false;
1519 for (const auto& [path, pid] : data)
1520 {
1521 auto findClass = pid.find("Class");
1522 if (findClass == pid.end())
1523 {
1524
1525 phosphor::logging::log<phosphor::logging::level::ERR>(
1526 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1527 "configurations");
1528 return ipmi::responseResponseError();
1529 }
1530 std::string type = std::get<std::string>(findClass->second);
1531 if (type == "fan")
1532 {
1533 auto findOutLimit = pid.find("OutLimitMin");
1534 if (findOutLimit == pid.end())
1535 {
1536
1537 phosphor::logging::log<phosphor::logging::level::ERR>(
1538 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1539 "configurations");
1540 return ipmi::responseResponseError();
1541 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001542 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001543 path, pidConfigurationIface, "OutLimitMin",
1544 static_cast<double>(offset));
1545 found = true;
1546 }
1547 }
1548 if (!found)
1549 {
1550 phosphor::logging::log<phosphor::logging::level::ERR>(
1551 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1552 return ipmi::responseResponseError();
1553 }
1554
1555 return ipmi::responseSuccess();
1556}
1557
1558ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1559 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001560{
1561 constexpr const size_t disableLimiting = 0x0;
1562
Vernon Mauery15419dd2019-05-24 09:40:30 -07001563 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001564 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001565 {
James Feist09f6b602019-08-08 11:30:03 -07001566 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001567 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001568 {
James Feist09f6b602019-08-08 11:30:03 -07001569 pathName = exitAirPathName;
1570 }
1571 else if (param1 == legacyPCHSensorNumber)
1572 {
1573 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001574 }
1575 else
1576 {
James Feistacc8a4e2019-04-02 14:23:57 -07001577 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001578 }
James Feist09f6b602019-08-08 11:30:03 -07001579 std::string path = getConfigPath(pathName);
1580 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1581 pidConfigurationIface, "SetPoint",
1582 static_cast<double>(param2));
1583 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001584 }
James Feistacc8a4e2019-04-02 14:23:57 -07001585 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001586 {
James Feistacc8a4e2019-04-02 14:23:57 -07001587 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001588
1589 // must be greater than 50 based on eps
1590 if (cfm < 50 && cfm != disableLimiting)
1591 {
James Feistacc8a4e2019-04-02 14:23:57 -07001592 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001593 }
1594
1595 try
1596 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001597 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001598 cfmLimitIface, "Limit",
1599 static_cast<double>(cfm));
1600 }
1601 catch (sdbusplus::exception_t& e)
1602 {
1603 phosphor::logging::log<phosphor::logging::level::ERR>(
1604 "ipmiOEMSetFscParameter: can't set cfm setting!",
1605 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001606 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001607 }
James Feistacc8a4e2019-04-02 14:23:57 -07001608 return ipmi::responseSuccess();
1609 }
1610 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1611 {
1612 constexpr const size_t maxDomainCount = 8;
1613 uint8_t requestedDomainMask = param1;
1614 boost::container::flat_map data = getPidConfigs();
1615 if (data.empty())
1616 {
1617
1618 phosphor::logging::log<phosphor::logging::level::ERR>(
1619 "ipmiOEMSetFscParameter: found no pid configurations!");
1620 return ipmi::responseResponseError();
1621 }
1622 size_t count = 0;
1623 for (const auto& [path, pid] : data)
1624 {
1625 auto findClass = pid.find("Class");
1626 if (findClass == pid.end())
1627 {
1628
1629 phosphor::logging::log<phosphor::logging::level::ERR>(
1630 "ipmiOEMSetFscParameter: found illegal pid "
1631 "configurations");
1632 return ipmi::responseResponseError();
1633 }
1634 std::string type = std::get<std::string>(findClass->second);
1635 if (type == "fan")
1636 {
1637 if (requestedDomainMask & (1 << count))
1638 {
1639 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001640 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001641 pidConfigurationIface, "OutLimitMax",
1642 static_cast<double>(param2));
1643 }
1644 count++;
1645 }
1646 }
1647 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001648 }
1649 else
1650 {
1651 // todo other command parts possibly
1652 // tcontrol is handled in peci now
1653 // fan speed offset not implemented yet
1654 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001655 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001656 }
1657}
1658
James Feistacc8a4e2019-04-02 14:23:57 -07001659ipmi::RspType<
1660 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1661 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001662{
James Feist09f6b602019-08-08 11:30:03 -07001663 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001664
Vernon Mauery15419dd2019-05-24 09:40:30 -07001665 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001666 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001667 {
James Feistacc8a4e2019-04-02 14:23:57 -07001668 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001669 {
James Feistacc8a4e2019-04-02 14:23:57 -07001670 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001671 }
1672
James Feist09f6b602019-08-08 11:30:03 -07001673 std::string pathName;
1674
1675 if (*param == legacyExitAirSensorNumber)
1676 {
1677 pathName = exitAirPathName;
1678 }
1679 else if (*param == legacyPCHSensorNumber)
1680 {
1681 pathName = pchPathName;
1682 }
1683 else
James Feistfaa4f222019-03-21 16:21:55 -07001684 {
James Feistacc8a4e2019-04-02 14:23:57 -07001685 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001686 }
James Feist09f6b602019-08-08 11:30:03 -07001687
1688 uint8_t setpoint = legacyDefaultSetpoint;
1689 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001690 if (path.size())
1691 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001692 Value val = ipmi::getDbusProperty(
1693 *dbus, "xyz.openbmc_project.EntityManager", path,
1694 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001695 setpoint = std::floor(std::get<double>(val) + 0.5);
1696 }
1697
1698 // old implementation used to return the "default" and current, we
1699 // don't make the default readily available so just make both the
1700 // same
James Feistfaa4f222019-03-21 16:21:55 -07001701
James Feistacc8a4e2019-04-02 14:23:57 -07001702 return ipmi::responseSuccess(
1703 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001704 }
James Feistacc8a4e2019-04-02 14:23:57 -07001705 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1706 {
1707 constexpr const size_t maxDomainCount = 8;
1708
1709 if (!param)
1710 {
1711 return ipmi::responseReqDataLenInvalid();
1712 }
1713 uint8_t requestedDomain = *param;
1714 if (requestedDomain >= maxDomainCount)
1715 {
1716 return ipmi::responseInvalidFieldRequest();
1717 }
1718
1719 boost::container::flat_map data = getPidConfigs();
1720 if (data.empty())
1721 {
1722 phosphor::logging::log<phosphor::logging::level::ERR>(
1723 "ipmiOEMGetFscParameter: found no pid configurations!");
1724 return ipmi::responseResponseError();
1725 }
1726 size_t count = 0;
1727 for (const auto& [_, pid] : data)
1728 {
1729 auto findClass = pid.find("Class");
1730 if (findClass == pid.end())
1731 {
1732 phosphor::logging::log<phosphor::logging::level::ERR>(
1733 "ipmiOEMGetFscParameter: found illegal pid "
1734 "configurations");
1735 return ipmi::responseResponseError();
1736 }
1737 std::string type = std::get<std::string>(findClass->second);
1738 if (type == "fan")
1739 {
1740 if (requestedDomain == count)
1741 {
1742 auto findOutLimit = pid.find("OutLimitMax");
1743 if (findOutLimit == pid.end())
1744 {
1745 phosphor::logging::log<phosphor::logging::level::ERR>(
1746 "ipmiOEMGetFscParameter: found illegal pid "
1747 "configurations");
1748 return ipmi::responseResponseError();
1749 }
1750
1751 return ipmi::responseSuccess(
1752 static_cast<uint8_t>(std::floor(
1753 std::get<double>(findOutLimit->second) + 0.5)));
1754 }
1755 else
1756 {
1757 count++;
1758 }
1759 }
1760 }
1761
1762 return ipmi::responseInvalidFieldRequest();
1763 }
1764 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001765 {
1766
1767 /*
1768 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001769 previous behavior didn't seem to prevent this, ignore the check for
1770 now.
James Feist5f957ca2019-03-14 15:33:55 -07001771
James Feistacc8a4e2019-04-02 14:23:57 -07001772 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001773 {
1774 phosphor::logging::log<phosphor::logging::level::ERR>(
1775 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001776 return IPMI_CC_REQ_DATA_LEN_INVALID;
1777 }
1778 */
1779 Value cfmLimit;
1780 Value cfmMaximum;
1781 try
1782 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001783 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001784 cfmLimitSettingPath, cfmLimitIface,
1785 "Limit");
1786 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001787 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001788 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1789 }
1790 catch (sdbusplus::exception_t& e)
1791 {
1792 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001793 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001794 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001795 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001796 }
1797
James Feistacc8a4e2019-04-02 14:23:57 -07001798 double cfmMax = std::get<double>(cfmMaximum);
1799 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001800
James Feistacc8a4e2019-04-02 14:23:57 -07001801 cfmLim = std::floor(cfmLim + 0.5);
1802 cfmMax = std::floor(cfmMax + 0.5);
1803 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1804 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001805
James Feistacc8a4e2019-04-02 14:23:57 -07001806 return ipmi::responseSuccess(
1807 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001808 }
James Feistacc8a4e2019-04-02 14:23:57 -07001809
James Feist5f957ca2019-03-14 15:33:55 -07001810 else
1811 {
1812 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001813 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001814 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001815 }
1816}
1817
Cheng C Yang773703a2019-08-15 09:41:11 +08001818using crConfigVariant =
1819 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
1820
1821int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1822 const crConfigVariant& value,
1823 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1824{
1825 boost::system::error_code ec;
1826 ctx->bus->yield_method_call<void>(
1827 *(ctx->yield), ec, "xyz.openbmc_project.Settings",
1828 "/xyz/openbmc_project/control/power_supply_redundancy",
1829 "org.freedesktop.DBus.Properties", "Set",
1830 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
1831 if (ec)
1832 {
1833 phosphor::logging::log<phosphor::logging::level::ERR>(
1834 "Failed to set dbus property to cold redundancy");
1835 return -1;
1836 }
1837
1838 return 0;
1839}
1840
1841int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1842 crConfigVariant& value,
1843 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1844{
1845 boost::system::error_code ec;
1846 value = ctx->bus->yield_method_call<crConfigVariant>(
1847 *(ctx->yield), ec, "xyz.openbmc_project.Settings",
1848 "/xyz/openbmc_project/control/power_supply_redundancy",
1849 "org.freedesktop.DBus.Properties", "Get",
1850 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
1851 if (ec)
1852 {
1853 phosphor::logging::log<phosphor::logging::level::ERR>(
1854 "Failed to get dbus property to cold redundancy");
1855 return -1;
1856 }
1857 return 0;
1858}
1859
1860uint8_t getPSUCount(void)
1861{
1862 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1863 ipmi::Value num;
1864 try
1865 {
1866 num = ipmi::getDbusProperty(
1867 *dbus, "xyz.openbmc_project.PSURedundancy",
1868 "/xyz/openbmc_project/control/power_supply_redundancy",
1869 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
1870 }
1871 catch (sdbusplus::exception_t& e)
1872 {
1873 phosphor::logging::log<phosphor::logging::level::ERR>(
1874 "Failed to get PSUNumber property from dbus interface");
1875 return 0;
1876 }
1877 uint8_t* pNum = std::get_if<uint8_t>(&num);
1878 if (!pNum)
1879 {
1880 phosphor::logging::log<phosphor::logging::level::ERR>(
1881 "Error to get PSU Number");
1882 return 0;
1883 }
1884 return *pNum;
1885}
1886
1887bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
1888{
1889 if (conf.size() < num)
1890 {
1891 phosphor::logging::log<phosphor::logging::level::ERR>(
1892 "Invalid PSU Ranking");
1893 return false;
1894 }
1895 std::set<uint8_t> confSet;
1896 for (uint8_t i = 0; i < num; i++)
1897 {
1898 if (conf[i] > num)
1899 {
1900 phosphor::logging::log<phosphor::logging::level::ERR>(
1901 "PSU Ranking is larger than current PSU number");
1902 return false;
1903 }
1904 confSet.emplace(conf[i]);
1905 }
1906
1907 if (confSet.size() != num)
1908 {
1909 phosphor::logging::log<phosphor::logging::level::ERR>(
1910 "duplicate PSU Ranking");
1911 return false;
1912 }
1913 return true;
1914}
1915
1916enum class crParameter
1917{
1918 crStatus = 0,
1919 crFeature = 1,
1920 rotationFeature = 2,
1921 rotationAlgo = 3,
1922 rotationPeriod = 4,
1923 numOfPSU = 5
1924};
1925
1926constexpr ipmi::Cc ccParameterNotSupported = 0x80;
1927static const constexpr uint32_t oneDay = 0x15180;
1928static const constexpr uint32_t oneMonth = 0xf53700;
1929static const constexpr uint8_t userSpecific = 0x01;
1930static const constexpr uint8_t crSetCompleted = 0;
1931ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
1932 uint8_t parameter,
1933 ipmi::message::Payload& payload)
1934{
1935 switch (static_cast<crParameter>(parameter))
1936 {
1937 case crParameter::crFeature:
1938 {
1939 uint8_t param1;
1940 if (payload.unpack(param1) || !payload.fullyUnpacked())
1941 {
1942 return ipmi::responseReqDataLenInvalid();
1943 }
1944 // ColdRedundancy Enable can only be true or flase
1945 if (param1 > 1)
1946 {
1947 return ipmi::responseInvalidFieldRequest();
1948 }
1949 if (setCRConfig(ctx, "ColdRedundancyEnabled",
1950 static_cast<bool>(param1)))
1951 {
1952 return ipmi::responseResponseError();
1953 }
1954 break;
1955 }
1956 case crParameter::rotationFeature:
1957 {
1958 uint8_t param1;
1959 if (payload.unpack(param1) || !payload.fullyUnpacked())
1960 {
1961 return ipmi::responseReqDataLenInvalid();
1962 }
1963 // Rotation Enable can only be true or false
1964 if (param1 > 1)
1965 {
1966 return ipmi::responseInvalidFieldRequest();
1967 }
1968 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
1969 {
1970 return ipmi::responseResponseError();
1971 }
1972 break;
1973 }
1974 case crParameter::rotationAlgo:
1975 {
1976 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
1977 std::string algoName;
1978 uint8_t param1;
1979 if (payload.unpack(param1))
1980 {
1981 return ipmi::responseReqDataLenInvalid();
1982 }
1983 switch (param1)
1984 {
1985 case 0:
1986 algoName = "xyz.openbmc_project.Control."
1987 "PowerSupplyRedundancy.Algo.bmcSpecific";
1988 break;
1989 case 1:
1990 algoName = "xyz.openbmc_project.Control."
1991 "PowerSupplyRedundancy.Algo.userSpecific";
1992 break;
1993 default:
1994 return ipmi::responseInvalidFieldRequest();
1995 }
1996 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
1997 {
1998 return ipmi::responseResponseError();
1999 }
2000
2001 uint8_t numberOfPSU = getPSUCount();
2002 if (!numberOfPSU)
2003 {
2004 return ipmi::responseResponseError();
2005 }
2006 std::vector<uint8_t> rankOrder;
2007
2008 if (param1 == userSpecific)
2009 {
2010 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2011 {
2012 ipmi::responseReqDataLenInvalid();
2013 }
2014 if (rankOrder.size() < numberOfPSU)
2015 {
2016 return ipmi::responseReqDataLenInvalid();
2017 }
2018
2019 if (!validateCRAlgo(rankOrder, numberOfPSU))
2020 {
2021 return ipmi::responseInvalidFieldRequest();
2022 }
2023 }
2024 else
2025 {
2026 if (rankOrder.size() > 0)
2027 {
2028 return ipmi::responseReqDataLenInvalid();
2029 }
2030 for (uint8_t i = 1; i <= numberOfPSU; i++)
2031 {
2032 rankOrder.emplace_back(i);
2033 }
2034 }
2035 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2036 {
2037 return ipmi::responseResponseError();
2038 }
2039 break;
2040 }
2041 case crParameter::rotationPeriod:
2042 {
2043 // Minimum Rotation period is One day (86400 seconds) and Max
2044 // Rotation Period is 6 month (0xf53700 seconds)
2045 uint32_t period;
2046 if (payload.unpack(period) || !payload.fullyUnpacked())
2047 {
2048 return ipmi::responseReqDataLenInvalid();
2049 }
2050 if ((period < oneDay) || (period > oneMonth))
2051 {
2052 return ipmi::responseInvalidFieldRequest();
2053 }
2054 if (setCRConfig(ctx, "PeriodOfRotation", period))
2055 {
2056 return ipmi::responseResponseError();
2057 }
2058 break;
2059 }
2060 default:
2061 {
2062 return ipmi::response(ccParameterNotSupported);
2063 }
2064 }
2065
2066 // TODO Halfwidth needs to set SetInProgress
2067 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002068 std::string("xyz.openbmc_project.Control."
2069 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002070 {
2071 return ipmi::responseResponseError();
2072 }
2073 return ipmi::responseSuccess(crSetCompleted);
2074}
2075
2076ipmi::RspType<std::variant<uint8_t, uint32_t, std::array<uint8_t, 5>>>
2077 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2078{
2079 crConfigVariant value;
2080 switch (static_cast<crParameter>(parameter))
2081 {
2082 case crParameter::crStatus:
2083 {
2084 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2085 {
2086 return ipmi::responseResponseError();
2087 }
2088 std::string* pStatus = std::get_if<std::string>(&value);
2089 if (!pStatus)
2090 {
2091 phosphor::logging::log<phosphor::logging::level::ERR>(
2092 "Error to get ColdRedundancyStatus property");
2093 return ipmi::responseResponseError();
2094 }
2095 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2096 auto status =
2097 server::PowerSupplyRedundancy::convertStatusFromString(
2098 *pStatus);
2099 switch (status)
2100 {
2101 case server::PowerSupplyRedundancy::Status::inProgress:
2102 return ipmi::responseSuccess(static_cast<uint8_t>(0));
2103
2104 case server::PowerSupplyRedundancy::Status::completed:
2105 return ipmi::responseSuccess(static_cast<uint8_t>(1));
2106 default:
2107 phosphor::logging::log<phosphor::logging::level::ERR>(
2108 "Error to get valid status");
2109 return ipmi::responseResponseError();
2110 }
2111 }
2112 case crParameter::crFeature:
2113 {
2114 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2115 {
2116 return ipmi::responseResponseError();
2117 }
2118 bool* pResponse = std::get_if<bool>(&value);
2119 if (!pResponse)
2120 {
2121 phosphor::logging::log<phosphor::logging::level::ERR>(
2122 "Error to get ColdRedundancyEnable property");
2123 return ipmi::responseResponseError();
2124 }
2125
2126 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse));
2127 }
2128 case crParameter::rotationFeature:
2129 {
2130 if (getCRConfig(ctx, "RotationEnabled", value))
2131 {
2132 return ipmi::responseResponseError();
2133 }
2134 bool* pResponse = std::get_if<bool>(&value);
2135 if (!pResponse)
2136 {
2137 phosphor::logging::log<phosphor::logging::level::ERR>(
2138 "Error to get RotationEnabled property");
2139 return ipmi::responseResponseError();
2140 }
2141 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse));
2142 }
2143 case crParameter::rotationAlgo:
2144 {
2145 if (getCRConfig(ctx, "RotationAlgorithm", value))
2146 {
2147 return ipmi::responseResponseError();
2148 }
2149
2150 std::string* pAlgo = std::get_if<std::string>(&value);
2151 if (!pAlgo)
2152 {
2153 phosphor::logging::log<phosphor::logging::level::ERR>(
2154 "Error to get RotationAlgorithm property");
2155 return ipmi::responseResponseError();
2156 }
2157 std::array<uint8_t, 5> response = {0, 0, 0, 0, 0};
2158 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2159 auto algo =
2160 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
2161 switch (algo)
2162 {
2163 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
2164 response[0] = 0;
2165 break;
2166 case server::PowerSupplyRedundancy::Algo::userSpecific:
2167 response[0] = 1;
2168 break;
2169 default:
2170 phosphor::logging::log<phosphor::logging::level::ERR>(
2171 "Error to get valid algo");
2172 return ipmi::responseResponseError();
2173 }
2174
2175 if (getCRConfig(ctx, "RotationRankOrder", value))
2176 {
2177 return ipmi::responseResponseError();
2178 }
2179 std::vector<uint8_t>* pResponse =
2180 std::get_if<std::vector<uint8_t>>(&value);
2181 if (!pResponse)
2182 {
2183 phosphor::logging::log<phosphor::logging::level::ERR>(
2184 "Error to get RotationRankOrder property");
2185 return ipmi::responseResponseError();
2186 }
2187 if (pResponse->size() + 1 > response.size())
2188 {
2189 phosphor::logging::log<phosphor::logging::level::ERR>(
2190 "Incorrect size of RotationAlgorithm property");
2191 return ipmi::responseResponseError();
2192 }
2193 std::copy(pResponse->begin(), pResponse->end(),
2194 response.begin() + 1);
2195 return ipmi::responseSuccess(response);
2196 }
2197 case crParameter::rotationPeriod:
2198 {
2199 if (getCRConfig(ctx, "PeriodOfRotation", value))
2200 {
2201 return ipmi::responseResponseError();
2202 }
2203 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2204 if (!pResponse)
2205 {
2206 phosphor::logging::log<phosphor::logging::level::ERR>(
2207 "Error to get RotationAlgorithm property");
2208 return ipmi::responseResponseError();
2209 }
2210 return ipmi::responseSuccess(*pResponse);
2211 }
2212 case crParameter::numOfPSU:
2213 {
2214 uint8_t numberOfPSU = getPSUCount();
2215 if (!numberOfPSU)
2216 {
2217 return ipmi::responseResponseError();
2218 }
2219 return ipmi::responseSuccess(numberOfPSU);
2220 }
2221 default:
2222 {
2223 return ipmi::response(ccParameterNotSupported);
2224 }
2225 }
2226}
2227
Zhu, Yungebe560b02019-04-21 21:19:21 -04002228ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2229 uint8_t faultState,
2230 uint8_t faultGroup,
2231 std::array<uint8_t, 8>& ledStateData)
2232{
2233 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2234 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2235 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2236 static const std::array<std::string, maxFaultType> faultNames = {
2237 "faultFan", "faultTemp", "faultPower",
2238 "faultDriveSlot", "faultSoftware", "faultMemory"};
2239 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2240 static constexpr const char* postfixValue = "/value";
2241
2242 constexpr uint8_t maxFaultSource = 0x4;
2243 constexpr uint8_t skipLEDs = 0xFF;
2244 constexpr uint8_t pinSize = 64;
2245 constexpr uint8_t groupSize = 16;
2246
2247 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2248 uint64_t resFIndex = 0;
2249 std::string resFType;
2250 std::string service;
2251 ObjectValueTree valueTree;
2252
2253 // Validate the source, fault type
2254 if ((sourceId >= maxFaultSource) ||
2255 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2256 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2257 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2258 {
2259 return ipmi::responseParmOutOfRange();
2260 }
2261
Vernon Mauery15419dd2019-05-24 09:40:30 -07002262 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002263 try
2264 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002265 service = getService(*dbus, intf, objpath);
2266 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002267 }
2268 catch (const std::exception& e)
2269 {
2270 phosphor::logging::log<phosphor::logging::level::ERR>(
2271 "No object implements interface",
2272 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2273 phosphor::logging::entry("INTF=%s", intf));
2274 return ipmi::responseResponseError();
2275 }
2276
2277 if (valueTree.empty())
2278 {
2279 phosphor::logging::log<phosphor::logging::level::ERR>(
2280 "No object implements interface",
2281 phosphor::logging::entry("INTF=%s", intf));
2282 return ipmi::responseResponseError();
2283 }
2284
2285 for (const auto& item : valueTree)
2286 {
2287 // find LedFault configuration
2288 auto interface =
2289 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2290 if (interface == item.second.end())
2291 {
2292 continue;
2293 }
2294
2295 // find matched fault type: faultMemmory / faultFan
2296 // find LedGpioPins/FaultIndex configuration
2297 auto propertyFaultType = interface->second.find("FaultType");
2298 auto propertyFIndex = interface->second.find("FaultIndex");
2299 auto ledIndex = interface->second.find("LedGpioPins");
2300
2301 if (propertyFaultType == interface->second.end() ||
2302 propertyFIndex == interface->second.end() ||
2303 ledIndex == interface->second.end())
2304 {
2305 continue;
2306 }
2307
2308 try
2309 {
2310 Value valIndex = propertyFIndex->second;
2311 resFIndex = std::get<uint64_t>(valIndex);
2312
2313 Value valFType = propertyFaultType->second;
2314 resFType = std::get<std::string>(valFType);
2315 }
2316 catch (const std::bad_variant_access& e)
2317 {
2318 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2319 return ipmi::responseResponseError();
2320 }
2321 // find the matched requested fault type: faultMemmory or faultFan
2322 if (resFType != faultNames[faultType])
2323 {
2324 continue;
2325 }
2326
2327 // read LedGpioPins data
2328 std::vector<uint64_t> ledgpios;
2329 std::variant<std::vector<uint64_t>> message;
2330
Vernon Mauery15419dd2019-05-24 09:40:30 -07002331 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002332 service.c_str(), (std::string(item.first)).c_str(),
2333 "org.freedesktop.DBus.Properties", "Get");
2334
2335 method.append("xyz.openbmc_project.Configuration.LedFault",
2336 "LedGpioPins");
2337
2338 try
2339 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002340 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002341 reply.read(message);
2342 ledgpios = std::get<std::vector<uint64_t>>(message);
2343 }
2344 catch (std::exception& e)
2345 {
2346 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2347 return ipmi::responseResponseError();
2348 }
2349
2350 // Check the size to be sure it will never overflow on groupSize
2351 if (ledgpios.size() > groupSize)
2352 {
2353 phosphor::logging::log<phosphor::logging::level::ERR>(
2354 "Fault gpio Pins out of range!");
2355 return ipmi::responseParmOutOfRange();
2356 }
2357 // Store data, according to command data bit index order
2358 for (int i = 0; i < ledgpios.size(); i++)
2359 {
2360 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2361 }
2362 }
2363
2364 switch (RemoteFaultType(faultType))
2365 {
2366 case (RemoteFaultType::fan):
2367 case (RemoteFaultType::memory):
2368 {
2369 if (faultGroup == skipLEDs)
2370 {
2371 return ipmi::responseSuccess();
2372 }
2373
2374 uint64_t ledState = 0;
2375 // calculate led state bit filed count, each byte has 8bits
2376 // the maximum bits will be 8 * 8 bits
2377 constexpr uint8_t size = sizeof(ledStateData) * 8;
2378 for (int i = 0; i < sizeof(ledStateData); i++)
2379 {
2380 ledState = (uint64_t)(ledState << 8);
2381 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2382 }
2383
2384 std::bitset<size> ledStateBits(ledState);
2385 std::string gpioValue;
2386 for (int i = 0; i < size; i++)
2387 { // skip invalid value
2388 if (ledFaultPins[i] == 0xFFFF)
2389 {
2390 continue;
2391 }
2392
2393 std::string device = sysGpioPath +
2394 std::to_string(ledFaultPins[i]) +
2395 postfixValue;
2396 std::fstream gpioFile;
2397
2398 gpioFile.open(device, std::ios::out);
2399
2400 if (!gpioFile.good())
2401 {
2402 phosphor::logging::log<phosphor::logging::level::ERR>(
2403 "Not Find Led Gpio Device!",
2404 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2405 return ipmi::responseResponseError();
2406 }
2407 gpioFile << std::to_string(
2408 static_cast<uint8_t>(ledStateBits[i]));
2409 gpioFile.close();
2410 }
2411 break;
2412 }
2413 default:
2414 {
2415 // now only support two fault types
2416 return ipmi::responseParmOutOfRange();
2417 }
2418 }
2419
2420 return ipmi::responseSuccess();
2421}
2422
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302423ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2424{
2425 uint8_t prodId = 0;
2426 try
2427 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002428 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302429 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002430 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302431 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2432 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002433 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302434 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2435 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2436 }
2437 catch (std::exception& e)
2438 {
2439 phosphor::logging::log<phosphor::logging::level::ERR>(
2440 "ipmiOEMReadBoardProductId: Product ID read failed!",
2441 phosphor::logging::entry("ERR=%s", e.what()));
2442 }
2443 return ipmi::responseSuccess(prodId);
2444}
2445
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002446ipmi::RspType<uint8_t /* restore status */>
2447 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2448{
2449 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2450
2451 if (clr != expClr)
2452 {
2453 return ipmi::responseInvalidFieldRequest();
2454 }
2455 constexpr uint8_t cmdStatus = 0;
2456 constexpr uint8_t cmdDefaultRestore = 0xaa;
2457 constexpr uint8_t cmdFullRestore = 0xbb;
2458 constexpr uint8_t cmdFormat = 0xcc;
2459
2460 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2461
2462 switch (cmd)
2463 {
2464 case cmdStatus:
2465 break;
2466 case cmdDefaultRestore:
2467 case cmdFullRestore:
2468 case cmdFormat:
2469 {
2470 // write file to rwfs root
2471 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2472 std::ofstream restoreFile(restoreOpFname);
2473 if (!restoreFile)
2474 {
2475 return ipmi::responseUnspecifiedError();
2476 }
2477 restoreFile << value << "\n";
2478 break;
2479 }
2480 default:
2481 return ipmi::responseInvalidFieldRequest();
2482 }
2483
2484 constexpr uint8_t restorePending = 0;
2485 constexpr uint8_t restoreComplete = 1;
2486
2487 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2488 ? restorePending
2489 : restoreComplete;
2490 return ipmi::responseSuccess(restoreStatus);
2491}
2492
Chen Yugang39736d52019-07-12 16:24:33 +08002493ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2494{
2495 uint8_t bmcSource;
2496 namespace nmi = sdbusplus::com::intel::Control::server;
2497
2498 try
2499 {
2500 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2501 std::string service =
2502 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2503 Value variant =
2504 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2505 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2506
2507 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2508 std::get<std::string>(variant)))
2509 {
2510 case nmi::NMISource::BMCSourceSignal::None:
2511 bmcSource = static_cast<uint8_t>(NmiSource::none);
2512 break;
2513 case nmi::NMISource::BMCSourceSignal::FpBtn:
2514 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
2515 break;
2516 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
2517 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
2518 break;
2519 case nmi::NMISource::BMCSourceSignal::PefMatch:
2520 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
2521 break;
2522 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2523 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2524 break;
2525 case nmi::NMISource::BMCSourceSignal::MemoryError:
2526 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2527 break;
2528 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
2529 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
2530 break;
2531 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
2532 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
2533 break;
2534 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
2535 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
2536 break;
2537 default:
2538 phosphor::logging::log<phosphor::logging::level::ERR>(
2539 "NMI source: invalid property!",
2540 phosphor::logging::entry(
2541 "PROP=%s", std::get<std::string>(variant).c_str()));
2542 return ipmi::responseResponseError();
2543 }
2544 }
2545 catch (sdbusplus::exception::SdBusError& e)
2546 {
2547 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2548 return ipmi::responseResponseError();
2549 }
2550
2551 return ipmi::responseSuccess(bmcSource);
2552}
2553
2554ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2555{
2556 namespace nmi = sdbusplus::com::intel::Control::server;
2557
2558 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2559 nmi::NMISource::BMCSourceSignal::None;
2560
2561 switch (NmiSource(sourceId))
2562 {
2563 case NmiSource::none:
2564 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2565 break;
2566 case NmiSource::fpBtn:
2567 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2568 break;
2569 case NmiSource::wdPreTimeout:
2570 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2571 break;
2572 case NmiSource::pefMatch:
2573 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2574 break;
2575 case NmiSource::chassisCmd:
2576 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2577 break;
2578 case NmiSource::memoryError:
2579 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2580 break;
2581 case NmiSource::pciSerrPerr:
2582 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2583 break;
2584 case NmiSource::southbridgeNmi:
2585 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2586 break;
2587 case NmiSource::chipsetNmi:
2588 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2589 break;
2590 default:
2591 phosphor::logging::log<phosphor::logging::level::ERR>(
2592 "NMI source: invalid property!");
2593 return ipmi::responseResponseError();
2594 }
2595
2596 try
2597 {
2598 // keep NMI signal source
2599 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2600 std::string service =
2601 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2602 setDbusProperty(
2603 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2604 oemNmiBmcSourceObjPathProp,
2605 sdbusplus::com::intel::Control::server::convertForMessage(
2606 bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002607 // set Enabled property to inform NMI source handling
2608 // to trigger a NMI_OUT BSOD.
2609 // if it's triggered by NMI source property changed,
2610 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2611 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2612 {
2613 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2614 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2615 static_cast<bool>(true));
2616 }
Chen Yugang39736d52019-07-12 16:24:33 +08002617 }
2618 catch (sdbusplus::exception_t& e)
2619 {
2620 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2621 return ipmi::responseResponseError();
2622 }
2623
2624 return ipmi::responseSuccess();
2625}
2626
James Feist63efafa2019-07-24 12:39:21 -07002627namespace dimmOffset
2628{
2629constexpr const char* dimmPower = "DimmPower";
2630constexpr const char* staticCltt = "StaticCltt";
2631constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2632constexpr const char* offsetInterface =
2633 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2634constexpr const char* property = "DimmOffset";
2635
2636}; // namespace dimmOffset
2637
2638ipmi::RspType<>
2639 ipmiOEMSetDimmOffset(uint8_t type,
2640 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2641{
2642 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2643 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2644 {
2645 return ipmi::responseInvalidFieldRequest();
2646 }
2647
2648 if (data.empty())
2649 {
2650 return ipmi::responseInvalidFieldRequest();
2651 }
2652 nlohmann::json json;
2653
2654 std::ifstream jsonStream(dimmOffsetFile);
2655 if (jsonStream.good())
2656 {
2657 json = nlohmann::json::parse(jsonStream, nullptr, false);
2658 if (json.is_discarded())
2659 {
2660 json = nlohmann::json();
2661 }
2662 jsonStream.close();
2663 }
2664
2665 std::string typeName;
2666 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2667 {
2668 typeName = dimmOffset::dimmPower;
2669 }
2670 else
2671 {
2672 typeName = dimmOffset::staticCltt;
2673 }
2674
2675 nlohmann::json& field = json[typeName];
2676
2677 for (const auto& [index, value] : data)
2678 {
2679 field[index] = value;
2680 }
2681
2682 for (nlohmann::json& val : field)
2683 {
2684 if (val == nullptr)
2685 {
2686 val = static_cast<uint8_t>(0);
2687 }
2688 }
2689
2690 std::ofstream output(dimmOffsetFile);
2691 if (!output.good())
2692 {
2693 std::cerr << "Error writing json file\n";
2694 return ipmi::responseResponseError();
2695 }
2696
2697 output << json.dump(4);
2698
2699 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2700 {
2701 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
2702
2703 std::variant<std::vector<uint8_t>> offsets =
2704 field.get<std::vector<uint8_t>>();
2705 auto call = bus->new_method_call(
2706 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
2707 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
2708 try
2709 {
2710 bus->call(call);
2711 }
2712 catch (sdbusplus::exception_t& e)
2713 {
2714 phosphor::logging::log<phosphor::logging::level::ERR>(
2715 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
2716 phosphor::logging::entry("ERR=%s", e.what()));
2717 return ipmi::responseResponseError();
2718 }
2719 }
2720
2721 return ipmi::responseSuccess();
2722}
2723
2724ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
2725{
2726
2727 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2728 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2729 {
2730 return ipmi::responseInvalidFieldRequest();
2731 }
2732
2733 std::ifstream jsonStream(dimmOffsetFile);
2734
2735 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
2736 if (json.is_discarded())
2737 {
2738 std::cerr << "File error in " << dimmOffsetFile << "\n";
2739 return ipmi::responseResponseError();
2740 }
2741
2742 std::string typeName;
2743 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2744 {
2745 typeName = dimmOffset::dimmPower;
2746 }
2747 else
2748 {
2749 typeName = dimmOffset::staticCltt;
2750 }
2751
2752 auto it = json.find(typeName);
2753 if (it == json.end())
2754 {
2755 return ipmi::responseInvalidFieldRequest();
2756 }
2757
2758 if (it->size() <= index)
2759 {
2760 return ipmi::responseInvalidFieldRequest();
2761 }
2762
2763 uint8_t resp = it->at(index).get<uint8_t>();
2764 return ipmi::responseSuccess(resp);
2765}
2766
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08002767namespace boot_options
2768{
2769
2770using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
2771using IpmiValue = uint8_t;
2772constexpr auto ipmiDefault = 0;
2773
2774std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
2775 {0x01, Source::Sources::Network},
2776 {0x02, Source::Sources::Disk},
2777 {0x05, Source::Sources::ExternalMedia},
2778 {0x0f, Source::Sources::RemovableMedia},
2779 {ipmiDefault, Source::Sources::Default}};
2780
2781std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
2782 {0x03, Mode::Modes::Safe},
2783 {0x06, Mode::Modes::Setup},
2784 {ipmiDefault, Mode::Modes::Regular}};
2785
2786std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
2787 {Source::Sources::Network, 0x01},
2788 {Source::Sources::Disk, 0x02},
2789 {Source::Sources::ExternalMedia, 0x05},
2790 {Source::Sources::RemovableMedia, 0x0f},
2791 {Source::Sources::Default, ipmiDefault}};
2792
2793std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
2794 {Mode::Modes::Safe, 0x03},
2795 {Mode::Modes::Setup, 0x06},
2796 {Mode::Modes::Regular, ipmiDefault}};
2797
2798static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
2799static constexpr auto bootSourceIntf =
2800 "xyz.openbmc_project.Control.Boot.Source";
2801static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
2802static constexpr auto persistentObjPath =
2803 "/xyz/openbmc_project/control/host0/boot";
2804static constexpr auto oneTimePath =
2805 "/xyz/openbmc_project/control/host0/boot/one_time";
2806static constexpr auto bootSourceProp = "BootSource";
2807static constexpr auto bootModeProp = "BootMode";
2808static constexpr auto oneTimeBootEnableProp = "Enabled";
2809static constexpr auto httpBootMode =
2810 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
2811
2812enum class BootOptionParameter : size_t
2813{
2814 setInProgress = 0x0,
2815 bootFlags = 0x5,
2816};
2817static constexpr uint8_t setComplete = 0x0;
2818static constexpr uint8_t setInProgress = 0x1;
2819static uint8_t transferStatus = setComplete;
2820static constexpr uint8_t setParmVersion = 0x01;
2821static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
2822static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
2823static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
2824static constexpr uint8_t httpBoot = 0xd;
2825static constexpr uint8_t bootSourceMask = 0x3c;
2826
2827} // namespace boot_options
2828
2829ipmi::RspType<uint8_t, // version
2830 uint8_t, // param
2831 uint8_t, // data0, dependent on parameter
2832 std::optional<uint8_t> // data1, dependent on parameter
2833 >
2834 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
2835{
2836 using namespace boot_options;
2837 uint8_t bootOption = 0;
2838
2839 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
2840 {
2841 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
2842 std::nullopt);
2843 }
2844
2845 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
2846 {
2847 phosphor::logging::log<phosphor::logging::level::ERR>(
2848 "Unsupported parameter");
2849 return ipmi::responseResponseError();
2850 }
2851
2852 try
2853 {
2854 auto oneTimeEnabled = false;
2855 // read one time Enabled property
2856 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2857 std::string service = getService(*dbus, enabledIntf, oneTimePath);
2858 Value variant = getDbusProperty(*dbus, service, oneTimePath,
2859 enabledIntf, oneTimeBootEnableProp);
2860 oneTimeEnabled = std::get<bool>(variant);
2861
2862 // get BootSource and BootMode properties
2863 // according to oneTimeEnable
2864 auto bootObjPath = oneTimePath;
2865 if (oneTimeEnabled == false)
2866 {
2867 bootObjPath = persistentObjPath;
2868 }
2869
2870 service = getService(*dbus, bootModeIntf, bootObjPath);
2871 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
2872 bootModeProp);
2873
2874 auto bootMode =
2875 Mode::convertModesFromString(std::get<std::string>(variant));
2876
2877 service = getService(*dbus, bootSourceIntf, bootObjPath);
2878 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
2879 bootSourceProp);
2880
2881 if (std::get<std::string>(variant) == httpBootMode)
2882 {
2883 bootOption = httpBoot;
2884 }
2885 else
2886 {
2887 auto bootSource = Source::convertSourcesFromString(
2888 std::get<std::string>(variant));
2889 bootOption = sourceDbusToIpmi.at(bootSource);
2890 if (Source::Sources::Default == bootSource)
2891 {
2892 bootOption = modeDbusToIpmi.at(bootMode);
2893 }
2894 }
2895
2896 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
2897 : setParmBootFlagsValidPermanent;
2898 bootOption <<= 2; // shift for responseconstexpr
2899 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
2900 bootOption);
2901 }
2902 catch (sdbusplus::exception_t& e)
2903 {
2904 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2905 return ipmi::responseResponseError();
2906 }
2907}
2908
2909ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
2910 std::optional<uint8_t> bootOption)
2911{
2912 using namespace boot_options;
2913 auto oneTimeEnabled = false;
2914
2915 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
2916 {
2917 if (bootOption)
2918 {
2919 return ipmi::responseReqDataLenInvalid();
2920 }
2921
2922 if (transferStatus == setInProgress)
2923 {
2924 phosphor::logging::log<phosphor::logging::level::ERR>(
2925 "boot option set in progress!");
2926 return ipmi::responseResponseError();
2927 }
2928
2929 transferStatus = bootParam;
2930 return ipmi::responseSuccess();
2931 }
2932
2933 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
2934 {
2935 phosphor::logging::log<phosphor::logging::level::ERR>(
2936 "Unsupported parameter");
2937 return ipmi::responseResponseError();
2938 }
2939
2940 if (!bootOption)
2941 {
2942 return ipmi::responseReqDataLenInvalid();
2943 }
2944
2945 if (((bootOption.value() & bootSourceMask) >> 2) !=
2946 httpBoot) // not http boot, exit
2947 {
2948 phosphor::logging::log<phosphor::logging::level::ERR>(
2949 "wrong boot option parameter!");
2950 return ipmi::responseParmOutOfRange();
2951 }
2952
2953 try
2954 {
2955 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
2956 setParmBootFlagsPermanent;
2957
2958 // read one time Enabled property
2959 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2960 std::string service = getService(*dbus, enabledIntf, oneTimePath);
2961 Value variant = getDbusProperty(*dbus, service, oneTimePath,
2962 enabledIntf, oneTimeBootEnableProp);
2963 oneTimeEnabled = std::get<bool>(variant);
2964
2965 /*
2966 * Check if the current boot setting is onetime or permanent, if the
2967 * request in the command is otherwise, then set the "Enabled"
2968 * property in one_time object path to 'True' to indicate onetime
2969 * and 'False' to indicate permanent.
2970 *
2971 * Once the onetime/permanent setting is applied, then the bootMode
2972 * and bootSource is updated for the corresponding object.
2973 */
2974 if (permanent == oneTimeEnabled)
2975 {
2976 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
2977 oneTimeBootEnableProp, !permanent);
2978 }
2979
2980 // set BootSource and BootMode properties
2981 // according to oneTimeEnable or persistent
2982 auto bootObjPath = oneTimePath;
2983 if (oneTimeEnabled == false)
2984 {
2985 bootObjPath = persistentObjPath;
2986 }
2987 std::string bootMode =
2988 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
2989 std::string bootSource = httpBootMode;
2990
2991 service = getService(*dbus, bootModeIntf, bootObjPath);
2992 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
2993 bootMode);
2994
2995 service = getService(*dbus, bootSourceIntf, bootObjPath);
2996 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
2997 bootSourceProp, bootSource);
2998 }
2999 catch (sdbusplus::exception_t& e)
3000 {
3001 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3002 return ipmi::responseResponseError();
3003 }
3004
3005 return ipmi::responseSuccess();
3006}
3007
Jason M. Bills64796042018-10-03 16:51:55 -07003008static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003009{
3010 phosphor::logging::log<phosphor::logging::level::INFO>(
3011 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07003012 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
3013 ipmiOEMWildcard,
3014 PRIVILEGE_USER); // wildcard default handler
3015 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
3016 ipmiOEMWildcard,
3017 PRIVILEGE_USER); // wildcard default handler
3018 ipmiPrintAndRegister(
3019 netfnIntcOEMGeneral,
3020 static_cast<ipmi_cmd_t>(
3021 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
3022 NULL, ipmiOEMGetChassisIdentifier,
3023 PRIVILEGE_USER); // get chassis identifier
3024 ipmiPrintAndRegister(
3025 netfnIntcOEMGeneral,
3026 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
3027 NULL, ipmiOEMSetSystemGUID,
3028 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003029
3030 // <Disable BMC System Reset Action>
3031 ipmi::registerHandler(
3032 ipmi::prioOemBase, netfnIntcOEMGeneral,
3033 static_cast<ipmi::Cmd>(
3034 IPMINetfnIntelOEMGeneralCmd::cmdDisableBMCSystemReset),
3035 ipmi::Privilege::Admin, ipmiOEMDisableBMCSystemReset);
3036 // <Get BMC Reset Disables>
3037 ipmi::registerHandler(
3038 ipmi::prioOemBase, netfnIntcOEMGeneral,
3039 static_cast<ipmi::Cmd>(
3040 IPMINetfnIntelOEMGeneralCmd::cmdGetBMCResetDisables),
3041 ipmi::Privilege::Admin, ipmiOEMGetBMCResetDisables);
3042
Jason M. Bills64796042018-10-03 16:51:55 -07003043 ipmiPrintAndRegister(
3044 netfnIntcOEMGeneral,
3045 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
3046 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
3047 ipmiPrintAndRegister(netfnIntcOEMGeneral,
3048 static_cast<ipmi_cmd_t>(
3049 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
3050 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
3051 ipmiPrintAndRegister(
3052 netfnIntcOEMGeneral,
3053 static_cast<ipmi_cmd_t>(
3054 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
3055 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003056
3057 ipmi::registerHandler(
3058 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
3059 static_cast<ipmi::Cmd>(
3060 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
3061 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
3062
Jason M. Bills64796042018-10-03 16:51:55 -07003063 ipmiPrintAndRegister(
3064 netfnIntcOEMGeneral,
3065 static_cast<ipmi_cmd_t>(
3066 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
3067 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3068 ipmiPrintAndRegister(
3069 netfnIntcOEMGeneral,
3070 static_cast<ipmi_cmd_t>(
3071 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
3072 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303073
3074 ipmi::registerHandler(
3075 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
3076 static_cast<ipmi::Cmd>(
3077 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
3078 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
3079
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303080 ipmi::registerHandler(
3081 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
3082 static_cast<ipmi::Cmd>(
3083 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
3084 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
3085
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003086 // <Get Processor Error Config>
3087 ipmi::registerHandler(
3088 ipmi::prioOemBase, netfnIntcOEMGeneral,
3089 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07003090 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003091 ipmi::Privilege::User, ipmiOEMGetProcessorErrConfig);
3092 // <Set Processor Error Config>
3093 ipmi::registerHandler(
3094 ipmi::prioOemBase, netfnIntcOEMGeneral,
3095 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07003096 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003097 ipmi::Privilege::Admin, ipmiOEMSetProcessorErrConfig);
3098
Yong Li703922d2018-11-06 13:25:31 +08003099 ipmiPrintAndRegister(netfnIntcOEMGeneral,
3100 static_cast<ipmi_cmd_t>(
3101 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
3102 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
3103 ipmiPrintAndRegister(netfnIntcOEMGeneral,
3104 static_cast<ipmi_cmd_t>(
3105 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
3106 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003107
3108 ipmiPrintAndRegister(
3109 netfnIntcOEMGeneral,
3110 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
3111 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
3112
James Feist5b693632019-07-09 09:06:09 -07003113 ipmi::registerHandler(
3114 ipmi::prioOemBase, netfnIntcOEMGeneral,
3115 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
3116 ipmi::Privilege::User, ipmiOEMGetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003117
James Feistacc8a4e2019-04-02 14:23:57 -07003118 ipmi::registerHandler(
3119 ipmi::prioOemBase, netfnIntcOEMGeneral,
3120 static_cast<ipmi::Cmd>(
3121 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
3122 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07003123
James Feistacc8a4e2019-04-02 14:23:57 -07003124 ipmi::registerHandler(
3125 ipmi::prioOemBase, netfnIntcOEMGeneral,
3126 static_cast<ipmi::Cmd>(
3127 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
3128 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
3129
3130 ipmi::registerHandler(
3131 ipmi::prioOemBase, netfnIntcOEMGeneral,
3132 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
3133 ipmi::Privilege::User, ipmiOEMSetFscParameter);
3134
3135 ipmi::registerHandler(
3136 ipmi::prioOemBase, netfnIntcOEMGeneral,
3137 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
3138 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003139
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303140 ipmi::registerHandler(
3141 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
3142 static_cast<ipmi::Cmd>(
3143 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId),
3144 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId);
3145
Chen Yugang39736d52019-07-12 16:24:33 +08003146 ipmi::registerHandler(
3147 ipmi::prioOemBase, netfnIntcOEMGeneral,
3148 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetNmiStatus),
3149 ipmi::Privilege::User, ipmiOEMGetNmiSource);
3150
3151 ipmi::registerHandler(
3152 ipmi::prioOemBase, netfnIntcOEMGeneral,
3153 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus),
3154 ipmi::Privilege::Operator, ipmiOEMSetNmiSource);
3155
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003156 ipmi::registerHandler(
3157 ipmi::prioOemBase, netfnIntcOEMGeneral,
3158 static_cast<ipmi::Cmd>(
3159 IPMINetfnIntelOEMGeneralCmd::cmdGetEfiBootOptions),
3160 ipmi::Privilege::User, ipmiOemGetEfiBootOptions);
3161
3162 ipmi::registerHandler(
3163 ipmi::prioOemBase, netfnIntcOEMGeneral,
3164 static_cast<ipmi::Cmd>(
3165 IPMINetfnIntelOEMGeneralCmd::cmdSetEfiBootOptions),
3166 ipmi::Privilege::Operator, ipmiOemSetEfiBootOptions);
3167
Kuiying Wang45f04982018-12-26 09:23:08 +08003168 ipmiPrintAndRegister(
3169 netfnIntcOEMGeneral,
3170 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
3171 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08003172 ipmiPrintAndRegister(
3173 netfnIntcOEMPlatform,
3174 static_cast<ipmi_cmd_t>(
3175 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
3176 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Zhu, Yungebe560b02019-04-21 21:19:21 -04003177 ipmi::registerHandler(
3178 ipmi::prioOemBase, netfnIntcOEMGeneral,
3179 static_cast<ipmi::Cmd>(
3180 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication),
3181 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003182
Cheng C Yang773703a2019-08-15 09:41:11 +08003183 ipmi::registerHandler(
3184 ipmi::prioOemBase, netfnIntcOEMGeneral,
3185 static_cast<ipmi::Cmd>(
3186 IPMINetfnIntelOEMGeneralCmd::cmdSetColdRedundancyConfig),
3187 ipmi::Privilege::User, ipmiOEMSetCRConfig);
3188 ipmi::registerHandler(
3189 ipmi::prioOemBase, netfnIntcOEMGeneral,
3190 static_cast<ipmi::Cmd>(
3191 IPMINetfnIntelOEMGeneralCmd::cmdGetColdRedundancyConfig),
3192 ipmi::Privilege::User, ipmiOEMGetCRConfig);
3193
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003194 registerHandler(prioOemBase, netfn::intel::oemGeneral,
3195 netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
3196 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003197
3198 ipmi::registerHandler(
3199 ipmi::prioOemBase, netfnIntcOEMGeneral,
3200 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetDimmOffset),
3201 ipmi::Privilege::Operator, ipmiOEMSetDimmOffset);
3202
3203 ipmi::registerHandler(
3204 ipmi::prioOemBase, netfnIntcOEMGeneral,
3205 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetDimmOffset),
3206 ipmi::Privilege::Operator, ipmiOEMGetDimmOffset);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003207}
3208
3209} // namespace ipmi