blob: 133815ddb717c8f4c4f204a2df3f14ddecd40364 [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>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053044#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080045
46namespace ipmi
47{
Jason M. Bills64796042018-10-03 16:51:55 -070048static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070049
50namespace netfn::intel
51{
52constexpr NetFn oemGeneral = netFnOemOne;
53constexpr Cmd cmdRestoreConfiguration = 0x02;
54} // namespace netfn::intel
55
Jason M. Bills64796042018-10-03 16:51:55 -070056static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080057
Suryakanth Sekard509eb92018-11-15 17:44:11 +053058static constexpr auto ethernetIntf =
59 "xyz.openbmc_project.Network.EthernetInterface";
60static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
61static constexpr auto networkService = "xyz.openbmc_project.Network";
62static constexpr auto networkRoot = "/xyz/openbmc_project/network";
63
Chen Yugang39736d52019-07-12 16:24:33 +080064static constexpr const char* oemNmiSourceIntf = "com.intel.Control.NMISource";
65static constexpr const char* oemNmiSourceObjPath =
66 "/com/intel/control/NMISource";
67static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
68static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
69
James Feist63efafa2019-07-24 12:39:21 -070070static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
71
Chen Yugang39736d52019-07-12 16:24:33 +080072enum class NmiSource : uint8_t
73{
74 none = 0,
75 fpBtn = 1,
76 wdPreTimeout = 2,
77 pefMatch = 3,
78 chassisCmd = 4,
79 memoryError = 5,
80 pciSerrPerr = 6,
81 southbridgeNmi = 7,
82 chipsetNmi = 8,
83};
84
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053085static constexpr const char* restricionModeService =
86 "xyz.openbmc_project.RestrictionMode.Manager";
87static constexpr const char* restricionModeBasePath =
88 "/xyz/openbmc_project/control/security/restriction_mode";
89static constexpr const char* restricionModeIntf =
90 "xyz.openbmc_project.Control.Security.RestrictionMode";
91static constexpr const char* restricionModeProperty = "RestrictionMode";
92
93static constexpr const char* specialModeService =
94 "xyz.openbmc_project.SpecialMode";
95static constexpr const char* specialModeBasePath =
96 "/xyz/openbmc_project/security/specialMode";
97static constexpr const char* specialModeIntf =
98 "xyz.openbmc_project.Security.SpecialMode";
99static constexpr const char* specialModeProperty = "SpecialMode";
100
101static constexpr const char* dBusPropertyIntf =
102 "org.freedesktop.DBus.Properties";
103static constexpr const char* dBusPropertyGetMethod = "Get";
104static constexpr const char* dBusPropertySetMethod = "Set";
105
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800106// return code: 0 successful
107int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
108{
109 std::string objpath = "/xyz/openbmc_project/FruDevice";
110 std::string intf = "xyz.openbmc_project.FruDeviceManager";
111 std::string service = getService(bus, intf, objpath);
112 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
113 if (valueTree.empty())
114 {
115 phosphor::logging::log<phosphor::logging::level::ERR>(
116 "No object implements interface",
117 phosphor::logging::entry("INTF=%s", intf.c_str()));
118 return -1;
119 }
120
Jason M. Bills64796042018-10-03 16:51:55 -0700121 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800122 {
123 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
124 if (interface == item.second.end())
125 {
126 continue;
127 }
128
129 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
130 if (property == interface->second.end())
131 {
132 continue;
133 }
134
135 try
136 {
137 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700138 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700139 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800140 {
141 phosphor::logging::log<phosphor::logging::level::ERR>(
142 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800143 return -1;
144 }
Jason M. Bills64796042018-10-03 16:51:55 -0700145 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800146 return 0;
147 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700148 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800149 {
Jason M. Bills64796042018-10-03 16:51:55 -0700150 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800151 return -1;
152 }
153 }
154 return -1;
155}
Jason M. Bills64796042018-10-03 16:51:55 -0700156
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800157ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
158 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700159 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800160{
Jason M. Bills64796042018-10-03 16:51:55 -0700161 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162 // Status code.
163 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700164 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800165 return rc;
166}
167
168// Returns the Chassis Identifier (serial #)
169ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
170 ipmi_request_t request,
171 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700172 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800173 ipmi_context_t context)
174{
175 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700176 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 {
Jason M. Bills64796042018-10-03 16:51:55 -0700178 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 return IPMI_CC_REQ_DATA_LEN_INVALID;
180 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700181 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
182 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 {
Jason M. Bills64796042018-10-03 16:51:55 -0700184 *dataLen = serial.size(); // length will never exceed response length
185 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800186 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700187 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800188 return IPMI_CC_OK;
189 }
Jason M. Bills64796042018-10-03 16:51:55 -0700190 *dataLen = 0;
191 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192}
193
194ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195 ipmi_request_t request,
196 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700197 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800198{
199 static constexpr size_t safeBufferLength = 50;
200 char buf[safeBufferLength] = {0};
201 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
202
Jason M. Bills64796042018-10-03 16:51:55 -0700203 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800204 {
Jason M. Bills64796042018-10-03 16:51:55 -0700205 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800206 return IPMI_CC_REQ_DATA_LEN_INVALID;
207 }
208
Jason M. Bills64796042018-10-03 16:51:55 -0700209 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800210
211 snprintf(
212 buf, safeBufferLength,
213 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
214 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
215 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
216 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
217 Data->node3, Data->node2, Data->node1);
218 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
219 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800220
221 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
222 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700223 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
224 std::string service = getService(*dbus, intf, objpath);
225 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800226 return IPMI_CC_OK;
227}
228
Jason M. Billsb02bf092019-08-15 13:01:56 -0700229ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
230 uint7_t reserved1)
231{
232 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
233
234 try
235 {
236 auto service =
237 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
238 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
239 bmcResetDisablesIntf, "ResetOnSMI",
240 !disableResetOnSMI);
241 }
242 catch (std::exception& e)
243 {
244 phosphor::logging::log<phosphor::logging::level::ERR>(
245 "Failed to set BMC reset disables",
246 phosphor::logging::entry("EXCEPTION=%s", e.what()));
247 return ipmi::responseUnspecifiedError();
248 }
249
250 return ipmi::responseSuccess();
251}
252
253ipmi::RspType<bool, // disableResetOnSMI
254 uint7_t // reserved
255 >
256 ipmiOEMGetBMCResetDisables()
257{
258 bool disableResetOnSMI = true;
259
260 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
261 try
262 {
263 auto service =
264 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
265 Value variant =
266 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
267 bmcResetDisablesIntf, "ResetOnSMI");
268 disableResetOnSMI = !std::get<bool>(variant);
269 }
270 catch (std::exception& e)
271 {
272 phosphor::logging::log<phosphor::logging::level::ERR>(
273 "Failed to get BMC reset disables",
274 phosphor::logging::entry("EXCEPTION=%s", e.what()));
275 return ipmi::responseUnspecifiedError();
276 }
277
278 return ipmi::responseSuccess(disableResetOnSMI, 0);
279}
280
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800281ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
282 ipmi_request_t request, ipmi_response_t response,
283 ipmi_data_len_t dataLen, ipmi_context_t context)
284{
285 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
286
Jason M. Bills64796042018-10-03 16:51:55 -0700287 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800288 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800289 *dataLen = 0;
290 return IPMI_CC_REQ_DATA_LEN_INVALID;
291 }
Jason M. Bills64796042018-10-03 16:51:55 -0700292 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293
Vernon Mauery15419dd2019-05-24 09:40:30 -0700294 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
295 std::string service = getService(*dbus, biosIntf, biosObjPath);
296 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
298 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700299 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800300 *dataLen = 1;
301 return IPMI_CC_OK;
302}
303
304ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
305 ipmi_request_t request,
306 ipmi_response_t response,
307 ipmi_data_len_t dataLen, ipmi_context_t context)
308{
309 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
310 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
311
312 if (*dataLen == 0)
313 {
Jason M. Bills64796042018-10-03 16:51:55 -0700314 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 return IPMI_CC_REQ_DATA_LEN_INVALID;
316 }
317
318 size_t reqDataLen = *dataLen;
319 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700320 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800321 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800322 return IPMI_CC_INVALID_FIELD_REQUEST;
323 }
324
325 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700326 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800327 {
328 case OEMDevEntityType::biosId:
329 {
330 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
331 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800332 return IPMI_CC_REQ_DATA_LEN_INVALID;
333 }
334
Vernon Mauery15419dd2019-05-24 09:40:30 -0700335 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
336 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800337 try
338 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700339 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800340 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700341 std::string& idString = std::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800342 if (req->offset >= idString.size())
343 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800344 return IPMI_CC_PARM_OUT_OF_RANGE;
345 }
Jason M. Bills64796042018-10-03 16:51:55 -0700346 size_t length = 0;
347 if (req->countToRead > (idString.size() - req->offset))
348 {
349 length = idString.size() - req->offset;
350 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800351 else
352 {
Jason M. Bills64796042018-10-03 16:51:55 -0700353 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800354 }
Jason M. Bills64796042018-10-03 16:51:55 -0700355 std::copy(idString.begin() + req->offset, idString.end(),
356 res->data);
357 res->resDatalen = length;
358 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800359 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700360 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800361 {
Jason M. Bills64796042018-10-03 16:51:55 -0700362 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800363 return IPMI_CC_UNSPECIFIED_ERROR;
364 }
365 }
366 break;
367
368 case OEMDevEntityType::devVer:
369 case OEMDevEntityType::sdrVer:
370 // TODO:
371 return IPMI_CC_ILLEGAL_COMMAND;
372 default:
373 return IPMI_CC_INVALID_FIELD_REQUEST;
374 }
375 return IPMI_CC_OK;
376}
377
378ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
379 ipmi_request_t request, ipmi_response_t response,
380 ipmi_data_len_t dataLen, ipmi_context_t context)
381{
382 if (*dataLen != 0)
383 {
Jason M. Bills64796042018-10-03 16:51:55 -0700384 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800385 return IPMI_CC_REQ_DATA_LEN_INVALID;
386 }
387
388 *dataLen = 1;
389 uint8_t* res = reinterpret_cast<uint8_t*>(response);
390 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
391 // AIC is available so that BIOS will not timeout repeatly which leads to
392 // slow booting.
393 *res = 0; // Byte1=Count of SlotPosition/FruID records.
394 return IPMI_CC_OK;
395}
396
Jason M. Bills64796042018-10-03 16:51:55 -0700397ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
398 ipmi_request_t request,
399 ipmi_response_t response,
400 ipmi_data_len_t dataLen,
401 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800402{
Jason M. Bills64796042018-10-03 16:51:55 -0700403 GetPowerRestoreDelayRes* resp =
404 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
405
406 if (*dataLen != 0)
407 {
408 *dataLen = 0;
409 return IPMI_CC_REQ_DATA_LEN_INVALID;
410 }
411
Vernon Mauery15419dd2019-05-24 09:40:30 -0700412 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700413 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700414 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700415 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700416 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700417 powerRestoreDelayIntf, powerRestoreDelayProp);
418
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700419 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700420 resp->byteLSB = delay;
421 resp->byteMSB = delay >> 8;
422
423 *dataLen = sizeof(GetPowerRestoreDelayRes);
424
425 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800426}
427
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800428static uint8_t bcdToDec(uint8_t val)
429{
430 return ((val / 16 * 10) + (val % 16));
431}
432
433// Allows an update utility or system BIOS to send the status of an embedded
434// firmware update attempt to the BMC. After received, BMC will create a logging
435// record.
436ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
437 uint8_t majorRevision,
438 uint8_t minorRevision,
439 uint32_t auxInfo)
440{
441 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700442 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800443 target = (target & selEvtTargetMask) >> selEvtTargetShift;
444
445 /* make sure the status is 0, 1, or 2 as per the spec */
446 if (status > 2)
447 {
448 return ipmi::response(ipmi::ccInvalidFieldRequest);
449 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700450 /* make sure the target is 0, 1, 2, or 4 as per the spec */
451 if (target > 4 || target == 3)
452 {
453 return ipmi::response(ipmi::ccInvalidFieldRequest);
454 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800455 /*orignal OEM command is to record OEM SEL.
456 But openbmc does not support OEM SEL, so we redirect it to redfish event
457 logging. */
458 std::string buildInfo;
459 std::string action;
460 switch (FWUpdateTarget(target))
461 {
462 case FWUpdateTarget::targetBMC:
463 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700464 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800465 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
466 " BuildID: " + std::to_string(auxInfo);
467 buildInfo += std::to_string(auxInfo);
468 break;
469 case FWUpdateTarget::targetBIOS:
470 firmware = "BIOS";
471 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700472 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800473 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
474 " minor: " +
475 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
476 " ReleaseNumber: " + // ASCII encoded
477 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
478 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
479 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
480 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
481 break;
482 case FWUpdateTarget::targetME:
483 firmware = "ME";
484 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700485 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800486 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
487 " minor2: " +
488 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
489 " build1: " +
490 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
491 " build2: " +
492 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
493 break;
494 case FWUpdateTarget::targetOEMEWS:
495 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700496 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800497 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
498 " BuildID: " + std::to_string(auxInfo);
499 break;
500 }
501
Jason M. Billsdc249272019-04-03 09:58:40 -0700502 static const std::string openBMCMessageRegistryVersion("0.1");
503 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
504
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800505 switch (status)
506 {
507 case 0x0:
508 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700509 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800510 break;
511 case 0x1:
512 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700513 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800514 break;
515 case 0x2:
516 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700517 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800518 break;
519 default:
520 action = "unknown";
521 break;
522 }
523
Jason M. Billsdc249272019-04-03 09:58:40 -0700524 std::string firmwareInstanceStr =
525 firmware + " instance: " + std::to_string(instance);
526 std::string message("[firmware update] " + firmwareInstanceStr +
527 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800528
529 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700530 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
531 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
532 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800533 return ipmi::responseSuccess();
534}
535
Jason M. Bills64796042018-10-03 16:51:55 -0700536ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
537 ipmi_request_t request,
538 ipmi_response_t response,
539 ipmi_data_len_t dataLen,
540 ipmi_context_t context)
541{
542 SetPowerRestoreDelayReq* data =
543 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
544 uint16_t delay = 0;
545
546 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
547 {
548 *dataLen = 0;
549 return IPMI_CC_REQ_DATA_LEN_INVALID;
550 }
551 delay = data->byteMSB;
552 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700553 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700554 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700555 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
556 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700557 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
558 *dataLen = 0;
559
560 return IPMI_CC_OK;
561}
562
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700563static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700564{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700565 static constexpr const char* cpuPresencePathPrefix =
566 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
567 static constexpr const char* cpuPresenceIntf =
568 "xyz.openbmc_project.Inventory.Item";
569 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
570 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
571 try
Jason M. Bills64796042018-10-03 16:51:55 -0700572 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700573 auto service =
574 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
575
576 ipmi::Value result = ipmi::getDbusProperty(
577 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
578 return std::get<bool>(result);
579 }
580 catch (const std::exception& e)
581 {
582 phosphor::logging::log<phosphor::logging::level::INFO>(
583 "Cannot find processor presence",
584 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
585 return false;
586 }
587}
588
589ipmi::RspType<bool, // CATERR Reset Enabled
590 bool, // ERR2 Reset Enabled
591 uint6_t, // reserved
592 uint8_t, // reserved, returns 0x3F
593 uint6_t, // CPU1 CATERR Count
594 uint2_t, // CPU1 Status
595 uint6_t, // CPU2 CATERR Count
596 uint2_t, // CPU2 Status
597 uint6_t, // CPU3 CATERR Count
598 uint2_t, // CPU3 Status
599 uint6_t, // CPU4 CATERR Count
600 uint2_t, // CPU4 Status
601 uint8_t // Crashdump Count
602 >
603 ipmiOEMGetProcessorErrConfig()
604{
605 bool resetOnCATERR = false;
606 bool resetOnERR2 = false;
607 uint6_t cpu1CATERRCount = 0;
608 uint6_t cpu2CATERRCount = 0;
609 uint6_t cpu3CATERRCount = 0;
610 uint6_t cpu4CATERRCount = 0;
611 uint8_t crashdumpCount = 0;
612 uint2_t cpu1Status =
613 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
614 uint2_t cpu2Status =
615 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
616 uint2_t cpu3Status =
617 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
618 uint2_t cpu4Status =
619 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
620
621 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
622 try
623 {
624 auto service = ipmi::getService(*busp, processorErrConfigIntf,
625 processorErrConfigObjPath);
626
627 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
628 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
629 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
630 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
631 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
632 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
633 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
634 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
635 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
636 }
637 catch (const std::exception& e)
638 {
639 phosphor::logging::log<phosphor::logging::level::ERR>(
640 "Failed to fetch processor error config",
641 phosphor::logging::entry("ERROR=%s", e.what()));
642 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700643 }
644
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700645 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
646 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
647 cpu2Status, cpu3CATERRCount, cpu3Status,
648 cpu4CATERRCount, cpu4Status, crashdumpCount);
649}
Jason M. Bills64796042018-10-03 16:51:55 -0700650
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700651ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
652 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
653 std::optional<bool> clearCPUErrorCount,
654 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
655{
656 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700657
658 try
659 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700660 auto service = ipmi::getService(*busp, processorErrConfigIntf,
661 processorErrConfigObjPath);
662 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
663 processorErrConfigIntf, "ResetOnCATERR",
664 resetOnCATERR);
665 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
666 processorErrConfigIntf, "ResetOnERR2",
667 resetOnERR2);
668 if (clearCPUErrorCount.value_or(false))
669 {
670 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700671 processorErrConfigIntf, "ErrorCountCPU1",
672 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700673 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700674 processorErrConfigIntf, "ErrorCountCPU2",
675 static_cast<uint8_t>(0));
676 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
677 processorErrConfigIntf, "ErrorCountCPU3",
678 static_cast<uint8_t>(0));
679 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
680 processorErrConfigIntf, "ErrorCountCPU4",
681 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700682 }
683 if (clearCrashdumpCount.value_or(false))
684 {
685 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700686 processorErrConfigIntf, "CrashdumpCount",
687 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700688 }
Jason M. Bills64796042018-10-03 16:51:55 -0700689 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700690 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700691 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800692 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700693 "Failed to set processor error config",
694 phosphor::logging::entry("EXCEPTION=%s", e.what()));
695 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700696 }
697
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700698 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700699}
700
Yong Li703922d2018-11-06 13:25:31 +0800701ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
702 ipmi_request_t request,
703 ipmi_response_t response,
704 ipmi_data_len_t dataLen,
705 ipmi_context_t context)
706{
707 GetOEMShutdownPolicyRes* resp =
708 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
709
710 if (*dataLen != 0)
711 {
712 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800713 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800714 *dataLen = 0;
715 return IPMI_CC_REQ_DATA_LEN_INVALID;
716 }
717
718 *dataLen = 0;
719
720 try
721 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700722 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800723 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700724 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
725 Value variant = getDbusProperty(
726 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
727 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800728
729 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
730 convertPolicyFromString(std::get<std::string>(variant)) ==
731 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
732 NoShutdownOnOCOT)
733 {
734 resp->policy = 0;
735 }
736 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
737 convertPolicyFromString(std::get<std::string>(variant)) ==
738 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
739 Policy::ShutdownOnOCOT)
740 {
741 resp->policy = 1;
742 }
743 else
744 {
745 phosphor::logging::log<phosphor::logging::level::ERR>(
746 "oem_set_shutdown_policy: invalid property!",
747 phosphor::logging::entry(
748 "PROP=%s", std::get<std::string>(variant).c_str()));
749 return IPMI_CC_UNSPECIFIED_ERROR;
750 }
Yong Li703922d2018-11-06 13:25:31 +0800751 // TODO needs to check if it is multi-node products,
752 // policy is only supported on node 3/4
753 resp->policySupport = shutdownPolicySupported;
754 }
755 catch (sdbusplus::exception_t& e)
756 {
757 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
758 return IPMI_CC_UNSPECIFIED_ERROR;
759 }
760
761 *dataLen = sizeof(GetOEMShutdownPolicyRes);
762 return IPMI_CC_OK;
763}
764
765ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
766 ipmi_request_t request,
767 ipmi_response_t response,
768 ipmi_data_len_t dataLen,
769 ipmi_context_t context)
770{
771 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800772 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
773 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
774 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800775
776 // TODO needs to check if it is multi-node products,
777 // policy is only supported on node 3/4
778 if (*dataLen != 1)
779 {
780 phosphor::logging::log<phosphor::logging::level::ERR>(
781 "oem_set_shutdown_policy: invalid input len!");
782 *dataLen = 0;
783 return IPMI_CC_REQ_DATA_LEN_INVALID;
784 }
785
786 *dataLen = 0;
787 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
788 {
789 phosphor::logging::log<phosphor::logging::level::ERR>(
790 "oem_set_shutdown_policy: invalid input!");
791 return IPMI_CC_INVALID_FIELD_REQUEST;
792 }
793
Yong Li0669d192019-05-06 14:01:46 +0800794 if (*req == noShutdownOnOCOT)
795 {
796 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
797 Policy::NoShutdownOnOCOT;
798 }
799 else
800 {
801 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
802 Policy::ShutdownOnOCOT;
803 }
804
Yong Li703922d2018-11-06 13:25:31 +0800805 try
806 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700807 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800808 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700809 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800810 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700811 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800812 oemShutdownPolicyObjPathProp,
813 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800814 }
815 catch (sdbusplus::exception_t& e)
816 {
817 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
818 return IPMI_CC_UNSPECIFIED_ERROR;
819 }
820
821 return IPMI_CC_OK;
822}
823
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530824/** @brief implementation for check the DHCP or not in IPv4
825 * @param[in] Channel - Channel number
826 * @returns true or false.
827 */
828static bool isDHCPEnabled(uint8_t Channel)
829{
830 try
831 {
832 auto ethdevice = getChannelName(Channel);
833 if (ethdevice.empty())
834 {
835 return false;
836 }
837 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700838 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530839 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700840 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
841 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530842 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700843 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530844 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
845 {
846 return true;
847 }
848 else
849 {
850 return false;
851 }
852 }
853 catch (sdbusplus::exception_t& e)
854 {
855 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
856 return true;
857 }
858}
859
860/** @brief implementes for check the DHCP or not in IPv6
861 * @param[in] Channel - Channel number
862 * @returns true or false.
863 */
864static bool isDHCPIPv6Enabled(uint8_t Channel)
865{
866
867 try
868 {
869 auto ethdevice = getChannelName(Channel);
870 if (ethdevice.empty())
871 {
872 return false;
873 }
874 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700875 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530876 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700877 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
878 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530879 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700880 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530881 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
882 {
883 return true;
884 }
885 else
886 {
887 return false;
888 }
889 }
890 catch (sdbusplus::exception_t& e)
891 {
892 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
893 return true;
894 }
895}
896
897/** @brief implementes the creating of default new user
898 * @param[in] userName - new username in 16 bytes.
899 * @param[in] userPassword - new password in 20 bytes
900 * @returns ipmi completion code.
901 */
902ipmi::RspType<> ipmiOEMSetUser2Activation(
903 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
904 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
905{
906 bool userState = false;
907 // Check for System Interface not exist and LAN should be static
908 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
909 {
910 ChannelInfo chInfo;
911 try
912 {
913 getChannelInfo(channel, chInfo);
914 }
915 catch (sdbusplus::exception_t& e)
916 {
917 phosphor::logging::log<phosphor::logging::level::ERR>(
918 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
919 phosphor::logging::entry("MSG: %s", e.description()));
920 return ipmi::response(ipmi::ccUnspecifiedError);
921 }
922 if (chInfo.mediumType ==
923 static_cast<uint8_t>(EChannelMediumType::systemInterface))
924 {
925 phosphor::logging::log<phosphor::logging::level::ERR>(
926 "ipmiOEMSetUser2Activation: system interface exist .");
927 return ipmi::response(ipmi::ccCommandNotAvailable);
928 }
929 else
930 {
931
932 if (chInfo.mediumType ==
933 static_cast<uint8_t>(EChannelMediumType::lan8032))
934 {
935 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
936 {
937 phosphor::logging::log<phosphor::logging::level::ERR>(
938 "ipmiOEMSetUser2Activation: DHCP enabled .");
939 return ipmi::response(ipmi::ccCommandNotAvailable);
940 }
941 }
942 }
943 }
944 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
945 if (ipmi::ccSuccess ==
946 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
947 {
948 if (enabledUsers > 1)
949 {
950 phosphor::logging::log<phosphor::logging::level::ERR>(
951 "ipmiOEMSetUser2Activation: more than one user is enabled.");
952 return ipmi::response(ipmi::ccCommandNotAvailable);
953 }
954 // Check the user 2 is enabled or not
955 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
956 if (userState == true)
957 {
958 phosphor::logging::log<phosphor::logging::level::ERR>(
959 "ipmiOEMSetUser2Activation: user 2 already enabled .");
960 return ipmi::response(ipmi::ccCommandNotAvailable);
961 }
962 }
963 else
964 {
965 return ipmi::response(ipmi::ccUnspecifiedError);
966 }
967
968#if BYTE_ORDER == LITTLE_ENDIAN
969 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
970#endif
971#if BYTE_ORDER == BIG_ENDIAN
972 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
973#endif
974
975 if (ipmi::ccSuccess ==
976 ipmiUserSetUserName(ipmiDefaultUserId,
977 reinterpret_cast<const char*>(userName.data())))
978 {
979 if (ipmi::ccSuccess ==
980 ipmiUserSetUserPassword(
981 ipmiDefaultUserId,
982 reinterpret_cast<const char*>(userPassword.data())))
983 {
984 if (ipmi::ccSuccess ==
985 ipmiUserSetPrivilegeAccess(
986 ipmiDefaultUserId,
987 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
988 privAccess, true))
989 {
990 phosphor::logging::log<phosphor::logging::level::INFO>(
991 "ipmiOEMSetUser2Activation: user created successfully ");
992 return ipmi::responseSuccess();
993 }
994 }
995 // we need to delete the default user id which added in this command as
996 // password / priv setting is failed.
997 ipmiUserSetUserName(ipmiDefaultUserId, "");
998 phosphor::logging::log<phosphor::logging::level::ERR>(
999 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1000 }
1001 else
1002 {
1003 phosphor::logging::log<phosphor::logging::level::ERR>(
1004 "ipmiOEMSetUser2Activation: Setting username failed.");
1005 }
1006
1007 return ipmi::response(ipmi::ccCommandNotAvailable);
1008}
1009
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301010/** @brief implementes setting password for special user
1011 * @param[in] specialUserIndex
1012 * @param[in] userPassword - new password in 20 bytes
1013 * @returns ipmi completion code.
1014 */
1015ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1016 uint8_t specialUserIndex,
1017 std::vector<uint8_t> userPassword)
1018{
1019 ChannelInfo chInfo;
1020 try
1021 {
1022 getChannelInfo(ctx->channel, chInfo);
1023 }
1024 catch (sdbusplus::exception_t& e)
1025 {
1026 phosphor::logging::log<phosphor::logging::level::ERR>(
1027 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1028 phosphor::logging::entry("MSG: %s", e.description()));
1029 return ipmi::responseUnspecifiedError();
1030 }
1031 if (chInfo.mediumType !=
1032 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(
1035 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1036 "interface");
1037 return ipmi::responseCommandNotAvailable();
1038 }
1039 if (specialUserIndex != 0)
1040 {
1041 phosphor::logging::log<phosphor::logging::level::ERR>(
1042 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1043 return ipmi::responseParmOutOfRange();
1044 }
1045 constexpr uint8_t minPasswordSizeRequired = 6;
1046 if (userPassword.size() < minPasswordSizeRequired ||
1047 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1048 {
1049 return ipmi::responseReqDataLenInvalid();
1050 }
1051 std::string passwd;
1052 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1053 userPassword.size());
1054 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
1055}
1056
Kuiying Wang45f04982018-12-26 09:23:08 +08001057namespace ledAction
1058{
1059using namespace sdbusplus::xyz::openbmc_project::Led::server;
1060std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
1061 {Physical::Action::Off, 0x00},
1062 {Physical::Action::On, 0x10},
1063 {Physical::Action::Blink, 0x01}};
1064
1065std::map<uint8_t, std::string> offsetObjPath = {
1066 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1067
1068} // namespace ledAction
1069
1070int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1071 const std::string& objPath, uint8_t& state)
1072{
1073 try
1074 {
1075 std::string service = getService(bus, intf, objPath);
1076 Value stateValue =
1077 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001078 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001079 state = ledAction::actionDbusToIpmi.at(
1080 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1081 convertActionFromString(strState));
1082 }
1083 catch (sdbusplus::exception::SdBusError& e)
1084 {
1085 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1086 return -1;
1087 }
1088 return 0;
1089}
1090
1091ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1092 ipmi_request_t request, ipmi_response_t response,
1093 ipmi_data_len_t dataLen, ipmi_context_t context)
1094{
1095 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1096 // LED Status
1097 //[1:0] = Reserved
1098 //[3:2] = Status(Amber)
1099 //[5:4] = Status(Green)
1100 //[7:6] = System Identify
1101 // Status definitions:
1102 // 00b = Off
1103 // 01b = Blink
1104 // 10b = On
1105 // 11b = invalid
1106 if (*dataLen != 0)
1107 {
1108 phosphor::logging::log<phosphor::logging::level::ERR>(
1109 "oem_get_led_status: invalid input len!");
1110 *dataLen = 0;
1111 return IPMI_CC_REQ_DATA_LEN_INVALID;
1112 }
1113
1114 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1115 *resp = 0;
1116 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001117 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001118 for (auto it = ledAction::offsetObjPath.begin();
1119 it != ledAction::offsetObjPath.end(); ++it)
1120 {
1121 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001122 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001123 {
1124 phosphor::logging::log<phosphor::logging::level::ERR>(
1125 "oem_get_led_status: fail to get ID LED status!");
1126 return IPMI_CC_UNSPECIFIED_ERROR;
1127 }
1128 *resp |= state << it->first;
1129 }
1130
1131 *dataLen = sizeof(*resp);
1132 return IPMI_CC_OK;
1133}
1134
Yong Li23737fe2019-02-19 08:49:55 +08001135ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1136 ipmi_request_t request,
1137 ipmi_response_t response,
1138 ipmi_data_len_t dataLen,
1139 ipmi_context_t context)
1140{
1141 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1142 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1143
1144 if (*dataLen == 0)
1145 {
1146 phosphor::logging::log<phosphor::logging::level::ERR>(
1147 "CfgHostSerial: invalid input len!",
1148 phosphor::logging::entry("LEN=%d", *dataLen));
1149 return IPMI_CC_REQ_DATA_LEN_INVALID;
1150 }
1151
1152 switch (req->command)
1153 {
1154 case getHostSerialCfgCmd:
1155 {
1156 if (*dataLen != 1)
1157 {
1158 phosphor::logging::log<phosphor::logging::level::ERR>(
1159 "CfgHostSerial: invalid input len!");
1160 *dataLen = 0;
1161 return IPMI_CC_REQ_DATA_LEN_INVALID;
1162 }
1163
1164 *dataLen = 0;
1165
1166 boost::process::ipstream is;
1167 std::vector<std::string> data;
1168 std::string line;
1169 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1170 boost::process::std_out > is);
1171
1172 while (c1.running() && std::getline(is, line) && !line.empty())
1173 {
1174 data.push_back(line);
1175 }
1176
1177 c1.wait();
1178 if (c1.exit_code())
1179 {
1180 phosphor::logging::log<phosphor::logging::level::ERR>(
1181 "CfgHostSerial:: error on execute",
1182 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1183 // Using the default value
1184 *resp = 0;
1185 }
1186 else
1187 {
1188 if (data.size() != 1)
1189 {
1190 phosphor::logging::log<phosphor::logging::level::ERR>(
1191 "CfgHostSerial:: error on read env");
1192 return IPMI_CC_UNSPECIFIED_ERROR;
1193 }
1194 try
1195 {
1196 unsigned long tmp = std::stoul(data[0]);
1197 if (tmp > std::numeric_limits<uint8_t>::max())
1198 {
1199 throw std::out_of_range("Out of range");
1200 }
1201 *resp = static_cast<uint8_t>(tmp);
1202 }
1203 catch (const std::invalid_argument& e)
1204 {
1205 phosphor::logging::log<phosphor::logging::level::ERR>(
1206 "invalid config ",
1207 phosphor::logging::entry("ERR=%s", e.what()));
1208 return IPMI_CC_UNSPECIFIED_ERROR;
1209 }
1210 catch (const std::out_of_range& e)
1211 {
1212 phosphor::logging::log<phosphor::logging::level::ERR>(
1213 "out_of_range config ",
1214 phosphor::logging::entry("ERR=%s", e.what()));
1215 return IPMI_CC_UNSPECIFIED_ERROR;
1216 }
1217 }
1218
1219 *dataLen = 1;
1220 break;
1221 }
1222 case setHostSerialCfgCmd:
1223 {
1224 if (*dataLen != sizeof(CfgHostSerialReq))
1225 {
1226 phosphor::logging::log<phosphor::logging::level::ERR>(
1227 "CfgHostSerial: invalid input len!");
1228 *dataLen = 0;
1229 return IPMI_CC_REQ_DATA_LEN_INVALID;
1230 }
1231
1232 *dataLen = 0;
1233
1234 if (req->parameter > HostSerialCfgParamMax)
1235 {
1236 phosphor::logging::log<phosphor::logging::level::ERR>(
1237 "CfgHostSerial: invalid input!");
1238 return IPMI_CC_INVALID_FIELD_REQUEST;
1239 }
1240
1241 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1242 std::to_string(req->parameter));
1243
1244 c1.wait();
1245 if (c1.exit_code())
1246 {
1247 phosphor::logging::log<phosphor::logging::level::ERR>(
1248 "CfgHostSerial:: error on execute",
1249 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1250 return IPMI_CC_UNSPECIFIED_ERROR;
1251 }
1252 break;
1253 }
1254 default:
1255 phosphor::logging::log<phosphor::logging::level::ERR>(
1256 "CfgHostSerial: invalid input!");
1257 *dataLen = 0;
1258 return IPMI_CC_INVALID_FIELD_REQUEST;
1259 }
1260
1261 return IPMI_CC_OK;
1262}
1263
James Feist91244a62019-02-19 15:04:54 -08001264constexpr const char* thermalModeInterface =
1265 "xyz.openbmc_project.Control.ThermalMode";
1266constexpr const char* thermalModePath =
1267 "/xyz/openbmc_project/control/thermal_mode";
1268
1269bool getFanProfileInterface(
1270 sdbusplus::bus::bus& bus,
1271 boost::container::flat_map<
1272 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1273{
1274 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1275 "GetAll");
1276 call.append(thermalModeInterface);
1277 try
1278 {
1279 auto data = bus.call(call);
1280 data.read(resp);
1281 }
1282 catch (sdbusplus::exception_t& e)
1283 {
1284 phosphor::logging::log<phosphor::logging::level::ERR>(
1285 "getFanProfileInterface: can't get thermal mode!",
1286 phosphor::logging::entry("ERR=%s", e.what()));
1287 return false;
1288 }
1289 return true;
1290}
1291
1292ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1293 ipmi_request_t request, ipmi_response_t response,
1294 ipmi_data_len_t dataLen, ipmi_context_t context)
1295{
1296
1297 if (*dataLen < 2 || *dataLen > 7)
1298 {
1299 phosphor::logging::log<phosphor::logging::level::ERR>(
1300 "ipmiOEMSetFanConfig: invalid input len!");
1301 *dataLen = 0;
1302 return IPMI_CC_REQ_DATA_LEN_INVALID;
1303 }
1304
1305 // todo: tell bios to only send first 2 bytes
1306
1307 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1308 boost::container::flat_map<
1309 std::string, std::variant<std::vector<std::string>, std::string>>
1310 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001311 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1312 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001313 {
1314 return IPMI_CC_UNSPECIFIED_ERROR;
1315 }
1316
1317 std::vector<std::string>* supported =
1318 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1319 if (supported == nullptr)
1320 {
1321 return IPMI_CC_INVALID_FIELD_REQUEST;
1322 }
1323 std::string mode;
1324 if (req->flags &
1325 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1326 {
1327 bool performanceMode =
1328 (req->flags & (1 << static_cast<uint8_t>(
1329 setFanProfileFlags::performAcousSelect))) > 0;
1330
1331 if (performanceMode)
1332 {
1333
1334 if (std::find(supported->begin(), supported->end(),
1335 "Performance") != supported->end())
1336 {
1337 mode = "Performance";
1338 }
1339 }
1340 else
1341 {
1342
1343 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1344 supported->end())
1345 {
1346 mode = "Acoustic";
1347 }
1348 }
1349 if (mode.empty())
1350 {
1351 return IPMI_CC_INVALID_FIELD_REQUEST;
1352 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001353 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001354 thermalModeInterface, "Current", mode);
1355 }
1356
1357 return IPMI_CC_OK;
1358}
1359
James Feist5b693632019-07-09 09:06:09 -07001360ipmi::RspType<uint8_t, // profile support map
1361 uint8_t, // fan control profile enable
1362 uint8_t, // flags
1363 uint32_t // dimm presence bit map
1364 >
1365 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001366{
James Feist91244a62019-02-19 15:04:54 -08001367 boost::container::flat_map<
1368 std::string, std::variant<std::vector<std::string>, std::string>>
1369 profileData;
1370
Vernon Mauery15419dd2019-05-24 09:40:30 -07001371 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1372 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001373 {
James Feist5b693632019-07-09 09:06:09 -07001374 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001375 }
1376
1377 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1378
1379 if (current == nullptr)
1380 {
1381 phosphor::logging::log<phosphor::logging::level::ERR>(
1382 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001383 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001384 }
1385 bool performance = (*current == "Performance");
1386
James Feist5b693632019-07-09 09:06:09 -07001387 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001388 if (performance)
1389 {
James Feist5b693632019-07-09 09:06:09 -07001390 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001391 }
1392
James Feist5b693632019-07-09 09:06:09 -07001393 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001394}
James Feist5f957ca2019-03-14 15:33:55 -07001395constexpr const char* cfmLimitSettingPath =
1396 "/xyz/openbmc_project/control/cfm_limit";
1397constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001398constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001399constexpr const size_t legacyPCHSensorNumber = 0x22;
1400constexpr const char* exitAirPathName = "Exit_Air";
1401constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001402constexpr const char* pidConfigurationIface =
1403 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001404
James Feist09f6b602019-08-08 11:30:03 -07001405static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001406{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001407 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001408 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001409 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1410 "/xyz/openbmc_project/object_mapper",
1411 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001412
James Feistacc8a4e2019-04-02 14:23:57 -07001413 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001414 std::string path;
1415 GetSubTreeType resp;
1416 try
1417 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001418 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001419 reply.read(resp);
1420 }
1421 catch (sdbusplus::exception_t&)
1422 {
1423 phosphor::logging::log<phosphor::logging::level::ERR>(
1424 "ipmiOEMGetFscParameter: mapper error");
1425 };
James Feist09f6b602019-08-08 11:30:03 -07001426 auto config =
1427 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1428 return pair.first.find(name) != std::string::npos;
1429 });
James Feistfaa4f222019-03-21 16:21:55 -07001430 if (config != resp.end())
1431 {
1432 path = std::move(config->first);
1433 }
1434 return path;
1435}
James Feist5f957ca2019-03-14 15:33:55 -07001436
James Feistacc8a4e2019-04-02 14:23:57 -07001437// flat map to make alphabetical
1438static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1439{
1440 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001441 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001442 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001443 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1444 "/xyz/openbmc_project/object_mapper",
1445 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001446
1447 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1448 GetSubTreeType resp;
1449
1450 try
1451 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001452 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001453 reply.read(resp);
1454 }
1455 catch (sdbusplus::exception_t&)
1456 {
1457 phosphor::logging::log<phosphor::logging::level::ERR>(
1458 "getFanConfigPaths: mapper error");
1459 };
1460 for (const auto& [path, objects] : resp)
1461 {
1462 if (objects.empty())
1463 {
1464 continue; // should be impossible
1465 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001466
1467 try
1468 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001469 ret.emplace(path,
1470 getAllDbusProperties(*dbus, objects[0].first, path,
1471 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001472 }
1473 catch (sdbusplus::exception_t& e)
1474 {
1475 phosphor::logging::log<phosphor::logging::level::ERR>(
1476 "getPidConfigs: can't get DbusProperties!",
1477 phosphor::logging::entry("ERR=%s", e.what()));
1478 }
James Feistacc8a4e2019-04-02 14:23:57 -07001479 }
1480 return ret;
1481}
1482
1483ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1484{
1485 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1486 if (data.empty())
1487 {
1488 return ipmi::responseResponseError();
1489 }
1490 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1491 for (const auto& [_, pid] : data)
1492 {
1493 auto findClass = pid.find("Class");
1494 if (findClass == pid.end())
1495 {
1496 phosphor::logging::log<phosphor::logging::level::ERR>(
1497 "ipmiOEMGetFscParameter: found illegal pid "
1498 "configurations");
1499 return ipmi::responseResponseError();
1500 }
1501 std::string type = std::get<std::string>(findClass->second);
1502 if (type == "fan")
1503 {
1504 auto findOutLimit = pid.find("OutLimitMin");
1505 if (findOutLimit == pid.end())
1506 {
1507 phosphor::logging::log<phosphor::logging::level::ERR>(
1508 "ipmiOEMGetFscParameter: found illegal pid "
1509 "configurations");
1510 return ipmi::responseResponseError();
1511 }
1512 // get the min out of all the offsets
1513 minOffset = std::min(
1514 minOffset,
1515 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1516 }
1517 }
1518 if (minOffset == std::numeric_limits<uint8_t>::max())
1519 {
1520 phosphor::logging::log<phosphor::logging::level::ERR>(
1521 "ipmiOEMGetFscParameter: found no fan configurations!");
1522 return ipmi::responseResponseError();
1523 }
1524
1525 return ipmi::responseSuccess(minOffset);
1526}
1527
1528ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1529{
1530 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1531 if (data.empty())
1532 {
1533
1534 phosphor::logging::log<phosphor::logging::level::ERR>(
1535 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1536 return ipmi::responseResponseError();
1537 }
1538
Vernon Mauery15419dd2019-05-24 09:40:30 -07001539 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001540 bool found = false;
1541 for (const auto& [path, pid] : data)
1542 {
1543 auto findClass = pid.find("Class");
1544 if (findClass == pid.end())
1545 {
1546
1547 phosphor::logging::log<phosphor::logging::level::ERR>(
1548 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1549 "configurations");
1550 return ipmi::responseResponseError();
1551 }
1552 std::string type = std::get<std::string>(findClass->second);
1553 if (type == "fan")
1554 {
1555 auto findOutLimit = pid.find("OutLimitMin");
1556 if (findOutLimit == pid.end())
1557 {
1558
1559 phosphor::logging::log<phosphor::logging::level::ERR>(
1560 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1561 "configurations");
1562 return ipmi::responseResponseError();
1563 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001564 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001565 path, pidConfigurationIface, "OutLimitMin",
1566 static_cast<double>(offset));
1567 found = true;
1568 }
1569 }
1570 if (!found)
1571 {
1572 phosphor::logging::log<phosphor::logging::level::ERR>(
1573 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1574 return ipmi::responseResponseError();
1575 }
1576
1577 return ipmi::responseSuccess();
1578}
1579
1580ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1581 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001582{
1583 constexpr const size_t disableLimiting = 0x0;
1584
Vernon Mauery15419dd2019-05-24 09:40:30 -07001585 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001586 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001587 {
James Feist09f6b602019-08-08 11:30:03 -07001588 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001589 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001590 {
James Feist09f6b602019-08-08 11:30:03 -07001591 pathName = exitAirPathName;
1592 }
1593 else if (param1 == legacyPCHSensorNumber)
1594 {
1595 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001596 }
1597 else
1598 {
James Feistacc8a4e2019-04-02 14:23:57 -07001599 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001600 }
James Feist09f6b602019-08-08 11:30:03 -07001601 std::string path = getConfigPath(pathName);
1602 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1603 pidConfigurationIface, "SetPoint",
1604 static_cast<double>(param2));
1605 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001606 }
James Feistacc8a4e2019-04-02 14:23:57 -07001607 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001608 {
James Feistacc8a4e2019-04-02 14:23:57 -07001609 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001610
1611 // must be greater than 50 based on eps
1612 if (cfm < 50 && cfm != disableLimiting)
1613 {
James Feistacc8a4e2019-04-02 14:23:57 -07001614 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001615 }
1616
1617 try
1618 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001619 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001620 cfmLimitIface, "Limit",
1621 static_cast<double>(cfm));
1622 }
1623 catch (sdbusplus::exception_t& e)
1624 {
1625 phosphor::logging::log<phosphor::logging::level::ERR>(
1626 "ipmiOEMSetFscParameter: can't set cfm setting!",
1627 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001628 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001629 }
James Feistacc8a4e2019-04-02 14:23:57 -07001630 return ipmi::responseSuccess();
1631 }
1632 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1633 {
1634 constexpr const size_t maxDomainCount = 8;
1635 uint8_t requestedDomainMask = param1;
1636 boost::container::flat_map data = getPidConfigs();
1637 if (data.empty())
1638 {
1639
1640 phosphor::logging::log<phosphor::logging::level::ERR>(
1641 "ipmiOEMSetFscParameter: found no pid configurations!");
1642 return ipmi::responseResponseError();
1643 }
1644 size_t count = 0;
1645 for (const auto& [path, pid] : data)
1646 {
1647 auto findClass = pid.find("Class");
1648 if (findClass == pid.end())
1649 {
1650
1651 phosphor::logging::log<phosphor::logging::level::ERR>(
1652 "ipmiOEMSetFscParameter: found illegal pid "
1653 "configurations");
1654 return ipmi::responseResponseError();
1655 }
1656 std::string type = std::get<std::string>(findClass->second);
1657 if (type == "fan")
1658 {
1659 if (requestedDomainMask & (1 << count))
1660 {
1661 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001662 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001663 pidConfigurationIface, "OutLimitMax",
1664 static_cast<double>(param2));
1665 }
1666 count++;
1667 }
1668 }
1669 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001670 }
1671 else
1672 {
1673 // todo other command parts possibly
1674 // tcontrol is handled in peci now
1675 // fan speed offset not implemented yet
1676 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001677 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001678 }
1679}
1680
James Feistacc8a4e2019-04-02 14:23:57 -07001681ipmi::RspType<
1682 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1683 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001684{
James Feist09f6b602019-08-08 11:30:03 -07001685 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001686
Vernon Mauery15419dd2019-05-24 09:40:30 -07001687 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001688 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001689 {
James Feistacc8a4e2019-04-02 14:23:57 -07001690 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001691 {
James Feistacc8a4e2019-04-02 14:23:57 -07001692 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001693 }
1694
James Feist09f6b602019-08-08 11:30:03 -07001695 std::string pathName;
1696
1697 if (*param == legacyExitAirSensorNumber)
1698 {
1699 pathName = exitAirPathName;
1700 }
1701 else if (*param == legacyPCHSensorNumber)
1702 {
1703 pathName = pchPathName;
1704 }
1705 else
James Feistfaa4f222019-03-21 16:21:55 -07001706 {
James Feistacc8a4e2019-04-02 14:23:57 -07001707 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001708 }
James Feist09f6b602019-08-08 11:30:03 -07001709
1710 uint8_t setpoint = legacyDefaultSetpoint;
1711 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001712 if (path.size())
1713 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001714 Value val = ipmi::getDbusProperty(
1715 *dbus, "xyz.openbmc_project.EntityManager", path,
1716 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001717 setpoint = std::floor(std::get<double>(val) + 0.5);
1718 }
1719
1720 // old implementation used to return the "default" and current, we
1721 // don't make the default readily available so just make both the
1722 // same
James Feistfaa4f222019-03-21 16:21:55 -07001723
James Feistacc8a4e2019-04-02 14:23:57 -07001724 return ipmi::responseSuccess(
1725 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001726 }
James Feistacc8a4e2019-04-02 14:23:57 -07001727 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1728 {
1729 constexpr const size_t maxDomainCount = 8;
1730
1731 if (!param)
1732 {
1733 return ipmi::responseReqDataLenInvalid();
1734 }
1735 uint8_t requestedDomain = *param;
1736 if (requestedDomain >= maxDomainCount)
1737 {
1738 return ipmi::responseInvalidFieldRequest();
1739 }
1740
1741 boost::container::flat_map data = getPidConfigs();
1742 if (data.empty())
1743 {
1744 phosphor::logging::log<phosphor::logging::level::ERR>(
1745 "ipmiOEMGetFscParameter: found no pid configurations!");
1746 return ipmi::responseResponseError();
1747 }
1748 size_t count = 0;
1749 for (const auto& [_, pid] : data)
1750 {
1751 auto findClass = pid.find("Class");
1752 if (findClass == pid.end())
1753 {
1754 phosphor::logging::log<phosphor::logging::level::ERR>(
1755 "ipmiOEMGetFscParameter: found illegal pid "
1756 "configurations");
1757 return ipmi::responseResponseError();
1758 }
1759 std::string type = std::get<std::string>(findClass->second);
1760 if (type == "fan")
1761 {
1762 if (requestedDomain == count)
1763 {
1764 auto findOutLimit = pid.find("OutLimitMax");
1765 if (findOutLimit == pid.end())
1766 {
1767 phosphor::logging::log<phosphor::logging::level::ERR>(
1768 "ipmiOEMGetFscParameter: found illegal pid "
1769 "configurations");
1770 return ipmi::responseResponseError();
1771 }
1772
1773 return ipmi::responseSuccess(
1774 static_cast<uint8_t>(std::floor(
1775 std::get<double>(findOutLimit->second) + 0.5)));
1776 }
1777 else
1778 {
1779 count++;
1780 }
1781 }
1782 }
1783
1784 return ipmi::responseInvalidFieldRequest();
1785 }
1786 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001787 {
1788
1789 /*
1790 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001791 previous behavior didn't seem to prevent this, ignore the check for
1792 now.
James Feist5f957ca2019-03-14 15:33:55 -07001793
James Feistacc8a4e2019-04-02 14:23:57 -07001794 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001795 {
1796 phosphor::logging::log<phosphor::logging::level::ERR>(
1797 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001798 return IPMI_CC_REQ_DATA_LEN_INVALID;
1799 }
1800 */
1801 Value cfmLimit;
1802 Value cfmMaximum;
1803 try
1804 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001805 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001806 cfmLimitSettingPath, cfmLimitIface,
1807 "Limit");
1808 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001809 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001810 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1811 }
1812 catch (sdbusplus::exception_t& e)
1813 {
1814 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001815 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001816 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001817 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001818 }
1819
James Feistacc8a4e2019-04-02 14:23:57 -07001820 double cfmMax = std::get<double>(cfmMaximum);
1821 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001822
James Feistacc8a4e2019-04-02 14:23:57 -07001823 cfmLim = std::floor(cfmLim + 0.5);
1824 cfmMax = std::floor(cfmMax + 0.5);
1825 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1826 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001827
James Feistacc8a4e2019-04-02 14:23:57 -07001828 return ipmi::responseSuccess(
1829 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001830 }
James Feistacc8a4e2019-04-02 14:23:57 -07001831
James Feist5f957ca2019-03-14 15:33:55 -07001832 else
1833 {
1834 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001835 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001836 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001837 }
1838}
1839
Cheng C Yang773703a2019-08-15 09:41:11 +08001840using crConfigVariant =
1841 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
1842
1843int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1844 const crConfigVariant& value,
1845 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1846{
1847 boost::system::error_code ec;
1848 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07001849 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08001850 "/xyz/openbmc_project/control/power_supply_redundancy",
1851 "org.freedesktop.DBus.Properties", "Set",
1852 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
1853 if (ec)
1854 {
1855 phosphor::logging::log<phosphor::logging::level::ERR>(
1856 "Failed to set dbus property to cold redundancy");
1857 return -1;
1858 }
1859
1860 return 0;
1861}
1862
1863int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1864 crConfigVariant& value,
1865 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1866{
1867 boost::system::error_code ec;
1868 value = ctx->bus->yield_method_call<crConfigVariant>(
James Feist28c72902019-09-16 10:34:07 -07001869 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08001870 "/xyz/openbmc_project/control/power_supply_redundancy",
1871 "org.freedesktop.DBus.Properties", "Get",
1872 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
1873 if (ec)
1874 {
1875 phosphor::logging::log<phosphor::logging::level::ERR>(
1876 "Failed to get dbus property to cold redundancy");
1877 return -1;
1878 }
1879 return 0;
1880}
1881
1882uint8_t getPSUCount(void)
1883{
1884 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1885 ipmi::Value num;
1886 try
1887 {
1888 num = ipmi::getDbusProperty(
1889 *dbus, "xyz.openbmc_project.PSURedundancy",
1890 "/xyz/openbmc_project/control/power_supply_redundancy",
1891 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
1892 }
1893 catch (sdbusplus::exception_t& e)
1894 {
1895 phosphor::logging::log<phosphor::logging::level::ERR>(
1896 "Failed to get PSUNumber property from dbus interface");
1897 return 0;
1898 }
1899 uint8_t* pNum = std::get_if<uint8_t>(&num);
1900 if (!pNum)
1901 {
1902 phosphor::logging::log<phosphor::logging::level::ERR>(
1903 "Error to get PSU Number");
1904 return 0;
1905 }
1906 return *pNum;
1907}
1908
1909bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
1910{
1911 if (conf.size() < num)
1912 {
1913 phosphor::logging::log<phosphor::logging::level::ERR>(
1914 "Invalid PSU Ranking");
1915 return false;
1916 }
1917 std::set<uint8_t> confSet;
1918 for (uint8_t i = 0; i < num; i++)
1919 {
1920 if (conf[i] > num)
1921 {
1922 phosphor::logging::log<phosphor::logging::level::ERR>(
1923 "PSU Ranking is larger than current PSU number");
1924 return false;
1925 }
1926 confSet.emplace(conf[i]);
1927 }
1928
1929 if (confSet.size() != num)
1930 {
1931 phosphor::logging::log<phosphor::logging::level::ERR>(
1932 "duplicate PSU Ranking");
1933 return false;
1934 }
1935 return true;
1936}
1937
1938enum class crParameter
1939{
1940 crStatus = 0,
1941 crFeature = 1,
1942 rotationFeature = 2,
1943 rotationAlgo = 3,
1944 rotationPeriod = 4,
1945 numOfPSU = 5
1946};
1947
1948constexpr ipmi::Cc ccParameterNotSupported = 0x80;
1949static const constexpr uint32_t oneDay = 0x15180;
1950static const constexpr uint32_t oneMonth = 0xf53700;
1951static const constexpr uint8_t userSpecific = 0x01;
1952static const constexpr uint8_t crSetCompleted = 0;
1953ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
1954 uint8_t parameter,
1955 ipmi::message::Payload& payload)
1956{
1957 switch (static_cast<crParameter>(parameter))
1958 {
1959 case crParameter::crFeature:
1960 {
1961 uint8_t param1;
1962 if (payload.unpack(param1) || !payload.fullyUnpacked())
1963 {
1964 return ipmi::responseReqDataLenInvalid();
1965 }
1966 // ColdRedundancy Enable can only be true or flase
1967 if (param1 > 1)
1968 {
1969 return ipmi::responseInvalidFieldRequest();
1970 }
1971 if (setCRConfig(ctx, "ColdRedundancyEnabled",
1972 static_cast<bool>(param1)))
1973 {
1974 return ipmi::responseResponseError();
1975 }
1976 break;
1977 }
1978 case crParameter::rotationFeature:
1979 {
1980 uint8_t param1;
1981 if (payload.unpack(param1) || !payload.fullyUnpacked())
1982 {
1983 return ipmi::responseReqDataLenInvalid();
1984 }
1985 // Rotation Enable can only be true or false
1986 if (param1 > 1)
1987 {
1988 return ipmi::responseInvalidFieldRequest();
1989 }
1990 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
1991 {
1992 return ipmi::responseResponseError();
1993 }
1994 break;
1995 }
1996 case crParameter::rotationAlgo:
1997 {
1998 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
1999 std::string algoName;
2000 uint8_t param1;
2001 if (payload.unpack(param1))
2002 {
2003 return ipmi::responseReqDataLenInvalid();
2004 }
2005 switch (param1)
2006 {
2007 case 0:
2008 algoName = "xyz.openbmc_project.Control."
2009 "PowerSupplyRedundancy.Algo.bmcSpecific";
2010 break;
2011 case 1:
2012 algoName = "xyz.openbmc_project.Control."
2013 "PowerSupplyRedundancy.Algo.userSpecific";
2014 break;
2015 default:
2016 return ipmi::responseInvalidFieldRequest();
2017 }
2018 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2019 {
2020 return ipmi::responseResponseError();
2021 }
2022
2023 uint8_t numberOfPSU = getPSUCount();
2024 if (!numberOfPSU)
2025 {
2026 return ipmi::responseResponseError();
2027 }
2028 std::vector<uint8_t> rankOrder;
2029
2030 if (param1 == userSpecific)
2031 {
2032 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2033 {
2034 ipmi::responseReqDataLenInvalid();
2035 }
2036 if (rankOrder.size() < numberOfPSU)
2037 {
2038 return ipmi::responseReqDataLenInvalid();
2039 }
2040
2041 if (!validateCRAlgo(rankOrder, numberOfPSU))
2042 {
2043 return ipmi::responseInvalidFieldRequest();
2044 }
2045 }
2046 else
2047 {
2048 if (rankOrder.size() > 0)
2049 {
2050 return ipmi::responseReqDataLenInvalid();
2051 }
2052 for (uint8_t i = 1; i <= numberOfPSU; i++)
2053 {
2054 rankOrder.emplace_back(i);
2055 }
2056 }
2057 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2058 {
2059 return ipmi::responseResponseError();
2060 }
2061 break;
2062 }
2063 case crParameter::rotationPeriod:
2064 {
2065 // Minimum Rotation period is One day (86400 seconds) and Max
2066 // Rotation Period is 6 month (0xf53700 seconds)
2067 uint32_t period;
2068 if (payload.unpack(period) || !payload.fullyUnpacked())
2069 {
2070 return ipmi::responseReqDataLenInvalid();
2071 }
2072 if ((period < oneDay) || (period > oneMonth))
2073 {
2074 return ipmi::responseInvalidFieldRequest();
2075 }
2076 if (setCRConfig(ctx, "PeriodOfRotation", period))
2077 {
2078 return ipmi::responseResponseError();
2079 }
2080 break;
2081 }
2082 default:
2083 {
2084 return ipmi::response(ccParameterNotSupported);
2085 }
2086 }
2087
2088 // TODO Halfwidth needs to set SetInProgress
2089 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002090 std::string("xyz.openbmc_project.Control."
2091 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002092 {
2093 return ipmi::responseResponseError();
2094 }
2095 return ipmi::responseSuccess(crSetCompleted);
2096}
2097
Cheng C Yangf41e3342019-09-10 04:47:23 +08002098ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::array<uint8_t, 5>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002099 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2100{
2101 crConfigVariant value;
2102 switch (static_cast<crParameter>(parameter))
2103 {
2104 case crParameter::crStatus:
2105 {
2106 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2107 {
2108 return ipmi::responseResponseError();
2109 }
2110 std::string* pStatus = std::get_if<std::string>(&value);
2111 if (!pStatus)
2112 {
2113 phosphor::logging::log<phosphor::logging::level::ERR>(
2114 "Error to get ColdRedundancyStatus property");
2115 return ipmi::responseResponseError();
2116 }
2117 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2118 auto status =
2119 server::PowerSupplyRedundancy::convertStatusFromString(
2120 *pStatus);
2121 switch (status)
2122 {
2123 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002124 return ipmi::responseSuccess(parameter,
2125 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002126
2127 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002128 return ipmi::responseSuccess(parameter,
2129 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002130 default:
2131 phosphor::logging::log<phosphor::logging::level::ERR>(
2132 "Error to get valid status");
2133 return ipmi::responseResponseError();
2134 }
2135 }
2136 case crParameter::crFeature:
2137 {
2138 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2139 {
2140 return ipmi::responseResponseError();
2141 }
2142 bool* pResponse = std::get_if<bool>(&value);
2143 if (!pResponse)
2144 {
2145 phosphor::logging::log<phosphor::logging::level::ERR>(
2146 "Error to get ColdRedundancyEnable property");
2147 return ipmi::responseResponseError();
2148 }
2149
Cheng C Yangf41e3342019-09-10 04:47:23 +08002150 return ipmi::responseSuccess(parameter,
2151 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002152 }
2153 case crParameter::rotationFeature:
2154 {
2155 if (getCRConfig(ctx, "RotationEnabled", value))
2156 {
2157 return ipmi::responseResponseError();
2158 }
2159 bool* pResponse = std::get_if<bool>(&value);
2160 if (!pResponse)
2161 {
2162 phosphor::logging::log<phosphor::logging::level::ERR>(
2163 "Error to get RotationEnabled property");
2164 return ipmi::responseResponseError();
2165 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002166 return ipmi::responseSuccess(parameter,
2167 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002168 }
2169 case crParameter::rotationAlgo:
2170 {
2171 if (getCRConfig(ctx, "RotationAlgorithm", value))
2172 {
2173 return ipmi::responseResponseError();
2174 }
2175
2176 std::string* pAlgo = std::get_if<std::string>(&value);
2177 if (!pAlgo)
2178 {
2179 phosphor::logging::log<phosphor::logging::level::ERR>(
2180 "Error to get RotationAlgorithm property");
2181 return ipmi::responseResponseError();
2182 }
2183 std::array<uint8_t, 5> response = {0, 0, 0, 0, 0};
2184 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2185 auto algo =
2186 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
2187 switch (algo)
2188 {
2189 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
2190 response[0] = 0;
2191 break;
2192 case server::PowerSupplyRedundancy::Algo::userSpecific:
2193 response[0] = 1;
2194 break;
2195 default:
2196 phosphor::logging::log<phosphor::logging::level::ERR>(
2197 "Error to get valid algo");
2198 return ipmi::responseResponseError();
2199 }
2200
2201 if (getCRConfig(ctx, "RotationRankOrder", value))
2202 {
2203 return ipmi::responseResponseError();
2204 }
2205 std::vector<uint8_t>* pResponse =
2206 std::get_if<std::vector<uint8_t>>(&value);
2207 if (!pResponse)
2208 {
2209 phosphor::logging::log<phosphor::logging::level::ERR>(
2210 "Error to get RotationRankOrder property");
2211 return ipmi::responseResponseError();
2212 }
2213 if (pResponse->size() + 1 > response.size())
2214 {
2215 phosphor::logging::log<phosphor::logging::level::ERR>(
2216 "Incorrect size of RotationAlgorithm property");
2217 return ipmi::responseResponseError();
2218 }
2219 std::copy(pResponse->begin(), pResponse->end(),
2220 response.begin() + 1);
Cheng C Yangf41e3342019-09-10 04:47:23 +08002221 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002222 }
2223 case crParameter::rotationPeriod:
2224 {
2225 if (getCRConfig(ctx, "PeriodOfRotation", value))
2226 {
2227 return ipmi::responseResponseError();
2228 }
2229 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2230 if (!pResponse)
2231 {
2232 phosphor::logging::log<phosphor::logging::level::ERR>(
2233 "Error to get RotationAlgorithm property");
2234 return ipmi::responseResponseError();
2235 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002236 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002237 }
2238 case crParameter::numOfPSU:
2239 {
2240 uint8_t numberOfPSU = getPSUCount();
2241 if (!numberOfPSU)
2242 {
2243 return ipmi::responseResponseError();
2244 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002245 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002246 }
2247 default:
2248 {
2249 return ipmi::response(ccParameterNotSupported);
2250 }
2251 }
2252}
2253
Zhu, Yungebe560b02019-04-21 21:19:21 -04002254ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2255 uint8_t faultState,
2256 uint8_t faultGroup,
2257 std::array<uint8_t, 8>& ledStateData)
2258{
2259 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2260 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2261 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2262 static const std::array<std::string, maxFaultType> faultNames = {
2263 "faultFan", "faultTemp", "faultPower",
2264 "faultDriveSlot", "faultSoftware", "faultMemory"};
2265 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2266 static constexpr const char* postfixValue = "/value";
2267
2268 constexpr uint8_t maxFaultSource = 0x4;
2269 constexpr uint8_t skipLEDs = 0xFF;
2270 constexpr uint8_t pinSize = 64;
2271 constexpr uint8_t groupSize = 16;
2272
2273 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2274 uint64_t resFIndex = 0;
2275 std::string resFType;
2276 std::string service;
2277 ObjectValueTree valueTree;
2278
2279 // Validate the source, fault type
2280 if ((sourceId >= maxFaultSource) ||
2281 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2282 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2283 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2284 {
2285 return ipmi::responseParmOutOfRange();
2286 }
2287
Vernon Mauery15419dd2019-05-24 09:40:30 -07002288 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002289 try
2290 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002291 service = getService(*dbus, intf, objpath);
2292 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002293 }
2294 catch (const std::exception& e)
2295 {
2296 phosphor::logging::log<phosphor::logging::level::ERR>(
2297 "No object implements interface",
2298 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2299 phosphor::logging::entry("INTF=%s", intf));
2300 return ipmi::responseResponseError();
2301 }
2302
2303 if (valueTree.empty())
2304 {
2305 phosphor::logging::log<phosphor::logging::level::ERR>(
2306 "No object implements interface",
2307 phosphor::logging::entry("INTF=%s", intf));
2308 return ipmi::responseResponseError();
2309 }
2310
2311 for (const auto& item : valueTree)
2312 {
2313 // find LedFault configuration
2314 auto interface =
2315 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2316 if (interface == item.second.end())
2317 {
2318 continue;
2319 }
2320
2321 // find matched fault type: faultMemmory / faultFan
2322 // find LedGpioPins/FaultIndex configuration
2323 auto propertyFaultType = interface->second.find("FaultType");
2324 auto propertyFIndex = interface->second.find("FaultIndex");
2325 auto ledIndex = interface->second.find("LedGpioPins");
2326
2327 if (propertyFaultType == interface->second.end() ||
2328 propertyFIndex == interface->second.end() ||
2329 ledIndex == interface->second.end())
2330 {
2331 continue;
2332 }
2333
2334 try
2335 {
2336 Value valIndex = propertyFIndex->second;
2337 resFIndex = std::get<uint64_t>(valIndex);
2338
2339 Value valFType = propertyFaultType->second;
2340 resFType = std::get<std::string>(valFType);
2341 }
2342 catch (const std::bad_variant_access& e)
2343 {
2344 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2345 return ipmi::responseResponseError();
2346 }
2347 // find the matched requested fault type: faultMemmory or faultFan
2348 if (resFType != faultNames[faultType])
2349 {
2350 continue;
2351 }
2352
2353 // read LedGpioPins data
2354 std::vector<uint64_t> ledgpios;
2355 std::variant<std::vector<uint64_t>> message;
2356
Vernon Mauery15419dd2019-05-24 09:40:30 -07002357 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002358 service.c_str(), (std::string(item.first)).c_str(),
2359 "org.freedesktop.DBus.Properties", "Get");
2360
2361 method.append("xyz.openbmc_project.Configuration.LedFault",
2362 "LedGpioPins");
2363
2364 try
2365 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002366 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002367 reply.read(message);
2368 ledgpios = std::get<std::vector<uint64_t>>(message);
2369 }
2370 catch (std::exception& e)
2371 {
2372 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2373 return ipmi::responseResponseError();
2374 }
2375
2376 // Check the size to be sure it will never overflow on groupSize
2377 if (ledgpios.size() > groupSize)
2378 {
2379 phosphor::logging::log<phosphor::logging::level::ERR>(
2380 "Fault gpio Pins out of range!");
2381 return ipmi::responseParmOutOfRange();
2382 }
2383 // Store data, according to command data bit index order
2384 for (int i = 0; i < ledgpios.size(); i++)
2385 {
2386 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2387 }
2388 }
2389
2390 switch (RemoteFaultType(faultType))
2391 {
2392 case (RemoteFaultType::fan):
2393 case (RemoteFaultType::memory):
2394 {
2395 if (faultGroup == skipLEDs)
2396 {
2397 return ipmi::responseSuccess();
2398 }
2399
2400 uint64_t ledState = 0;
2401 // calculate led state bit filed count, each byte has 8bits
2402 // the maximum bits will be 8 * 8 bits
2403 constexpr uint8_t size = sizeof(ledStateData) * 8;
2404 for (int i = 0; i < sizeof(ledStateData); i++)
2405 {
2406 ledState = (uint64_t)(ledState << 8);
2407 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2408 }
2409
2410 std::bitset<size> ledStateBits(ledState);
2411 std::string gpioValue;
2412 for (int i = 0; i < size; i++)
2413 { // skip invalid value
2414 if (ledFaultPins[i] == 0xFFFF)
2415 {
2416 continue;
2417 }
2418
2419 std::string device = sysGpioPath +
2420 std::to_string(ledFaultPins[i]) +
2421 postfixValue;
2422 std::fstream gpioFile;
2423
2424 gpioFile.open(device, std::ios::out);
2425
2426 if (!gpioFile.good())
2427 {
2428 phosphor::logging::log<phosphor::logging::level::ERR>(
2429 "Not Find Led Gpio Device!",
2430 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2431 return ipmi::responseResponseError();
2432 }
2433 gpioFile << std::to_string(
2434 static_cast<uint8_t>(ledStateBits[i]));
2435 gpioFile.close();
2436 }
2437 break;
2438 }
2439 default:
2440 {
2441 // now only support two fault types
2442 return ipmi::responseParmOutOfRange();
2443 }
2444 }
2445
2446 return ipmi::responseSuccess();
2447}
2448
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302449ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2450{
2451 uint8_t prodId = 0;
2452 try
2453 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002454 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302455 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002456 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302457 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2458 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002459 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302460 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2461 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2462 }
2463 catch (std::exception& e)
2464 {
2465 phosphor::logging::log<phosphor::logging::level::ERR>(
2466 "ipmiOEMReadBoardProductId: Product ID read failed!",
2467 phosphor::logging::entry("ERR=%s", e.what()));
2468 }
2469 return ipmi::responseSuccess(prodId);
2470}
2471
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302472/** @brief implements the get security mode command
2473 * @param ctx - ctx pointer
2474 *
2475 * @returns IPMI completion code with following data
2476 * - restriction mode value - As specified in
2477 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2478 * - special mode value - As specified in
2479 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2480 */
2481ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2482{
2483 namespace securityNameSpace =
2484 sdbusplus::xyz::openbmc_project::Control::Security::server;
2485 uint8_t restrictionModeValue = 0;
2486 uint8_t specialModeValue = 0;
2487
2488 boost::system::error_code ec;
2489 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002490 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302491 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2492 restricionModeProperty);
2493 if (ec)
2494 {
2495 phosphor::logging::log<phosphor::logging::level::ERR>(
2496 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2497 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2498 return ipmi::responseUnspecifiedError();
2499 }
2500 restrictionModeValue = static_cast<uint8_t>(
2501 securityNameSpace::RestrictionMode::convertModesFromString(
2502 std::get<std::string>(varRestrMode)));
2503 auto varSpecialMode = ctx->bus->yield_method_call<std::variant<uint8_t>>(
James Feist28c72902019-09-16 10:34:07 -07002504 ctx->yield, ec, specialModeService, specialModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302505 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2506 specialModeProperty);
2507 if (ec)
2508 {
2509 phosphor::logging::log<phosphor::logging::level::ERR>(
2510 "ipmiGetSecurityMode: failed to get SpecialMode property",
2511 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2512 // fall through, let us not worry about SpecialMode property, which is
2513 // not required in user scenario
2514 }
2515 else
2516 {
2517 specialModeValue = std::get<uint8_t>(varSpecialMode);
2518 }
2519 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2520}
2521
2522/** @brief implements the set security mode command
2523 * Command allows to upgrade the restriction mode and won't allow
2524 * to downgrade from system interface
2525 * @param ctx - ctx pointer
2526 * @param restrictionMode - restriction mode value to be set.
2527 *
2528 * @returns IPMI completion code
2529 */
2530ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
2531 uint8_t restrictionMode)
2532{
2533 namespace securityNameSpace =
2534 sdbusplus::xyz::openbmc_project::Control::Security::server;
2535
2536 ChannelInfo chInfo;
2537 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2538 {
2539 phosphor::logging::log<phosphor::logging::level::ERR>(
2540 "ipmiSetSecurityMode: Failed to get Channel Info",
2541 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2542 return ipmi::responseUnspecifiedError();
2543 }
2544 auto reqMode =
2545 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2546
2547 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2548 (reqMode >
2549 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2550 {
2551 return ipmi::responseInvalidFieldRequest();
2552 }
2553
2554 boost::system::error_code ec;
2555 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002556 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302557 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2558 restricionModeProperty);
2559 if (ec)
2560 {
2561 phosphor::logging::log<phosphor::logging::level::ERR>(
2562 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2563 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2564 return ipmi::responseUnspecifiedError();
2565 }
2566 auto currentRestrictionMode =
2567 securityNameSpace::RestrictionMode::convertModesFromString(
2568 std::get<std::string>(varRestrMode));
2569
2570 if (chInfo.mediumType !=
2571 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2572 currentRestrictionMode > reqMode)
2573 {
2574 phosphor::logging::log<phosphor::logging::level::ERR>(
2575 "ipmiSetSecurityMode - Downgrading security mode not supported "
2576 "through system interface",
2577 phosphor::logging::entry(
2578 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2579 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2580 return ipmi::responseCommandNotAvailable();
2581 }
2582
2583 ec.clear();
2584 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002585 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302586 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2587 restricionModeProperty,
2588 static_cast<std::variant<std::string>>(
2589 securityNameSpace::convertForMessage(reqMode)));
2590
2591 if (ec)
2592 {
2593 phosphor::logging::log<phosphor::logging::level::ERR>(
2594 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2595 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2596 return ipmi::responseUnspecifiedError();
2597 }
2598 return ipmi::responseSuccess();
2599}
2600
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002601ipmi::RspType<uint8_t /* restore status */>
2602 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2603{
2604 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2605
2606 if (clr != expClr)
2607 {
2608 return ipmi::responseInvalidFieldRequest();
2609 }
2610 constexpr uint8_t cmdStatus = 0;
2611 constexpr uint8_t cmdDefaultRestore = 0xaa;
2612 constexpr uint8_t cmdFullRestore = 0xbb;
2613 constexpr uint8_t cmdFormat = 0xcc;
2614
2615 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2616
2617 switch (cmd)
2618 {
2619 case cmdStatus:
2620 break;
2621 case cmdDefaultRestore:
2622 case cmdFullRestore:
2623 case cmdFormat:
2624 {
2625 // write file to rwfs root
2626 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2627 std::ofstream restoreFile(restoreOpFname);
2628 if (!restoreFile)
2629 {
2630 return ipmi::responseUnspecifiedError();
2631 }
2632 restoreFile << value << "\n";
2633 break;
2634 }
2635 default:
2636 return ipmi::responseInvalidFieldRequest();
2637 }
2638
2639 constexpr uint8_t restorePending = 0;
2640 constexpr uint8_t restoreComplete = 1;
2641
2642 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2643 ? restorePending
2644 : restoreComplete;
2645 return ipmi::responseSuccess(restoreStatus);
2646}
2647
Chen Yugang39736d52019-07-12 16:24:33 +08002648ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2649{
2650 uint8_t bmcSource;
2651 namespace nmi = sdbusplus::com::intel::Control::server;
2652
2653 try
2654 {
2655 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2656 std::string service =
2657 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2658 Value variant =
2659 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2660 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2661
2662 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2663 std::get<std::string>(variant)))
2664 {
2665 case nmi::NMISource::BMCSourceSignal::None:
2666 bmcSource = static_cast<uint8_t>(NmiSource::none);
2667 break;
2668 case nmi::NMISource::BMCSourceSignal::FpBtn:
2669 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
2670 break;
2671 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
2672 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
2673 break;
2674 case nmi::NMISource::BMCSourceSignal::PefMatch:
2675 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
2676 break;
2677 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2678 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2679 break;
2680 case nmi::NMISource::BMCSourceSignal::MemoryError:
2681 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2682 break;
2683 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
2684 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
2685 break;
2686 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
2687 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
2688 break;
2689 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
2690 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
2691 break;
2692 default:
2693 phosphor::logging::log<phosphor::logging::level::ERR>(
2694 "NMI source: invalid property!",
2695 phosphor::logging::entry(
2696 "PROP=%s", std::get<std::string>(variant).c_str()));
2697 return ipmi::responseResponseError();
2698 }
2699 }
2700 catch (sdbusplus::exception::SdBusError& e)
2701 {
2702 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2703 return ipmi::responseResponseError();
2704 }
2705
2706 return ipmi::responseSuccess(bmcSource);
2707}
2708
2709ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2710{
2711 namespace nmi = sdbusplus::com::intel::Control::server;
2712
2713 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2714 nmi::NMISource::BMCSourceSignal::None;
2715
2716 switch (NmiSource(sourceId))
2717 {
2718 case NmiSource::none:
2719 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2720 break;
2721 case NmiSource::fpBtn:
2722 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2723 break;
2724 case NmiSource::wdPreTimeout:
2725 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2726 break;
2727 case NmiSource::pefMatch:
2728 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2729 break;
2730 case NmiSource::chassisCmd:
2731 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2732 break;
2733 case NmiSource::memoryError:
2734 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2735 break;
2736 case NmiSource::pciSerrPerr:
2737 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2738 break;
2739 case NmiSource::southbridgeNmi:
2740 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2741 break;
2742 case NmiSource::chipsetNmi:
2743 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2744 break;
2745 default:
2746 phosphor::logging::log<phosphor::logging::level::ERR>(
2747 "NMI source: invalid property!");
2748 return ipmi::responseResponseError();
2749 }
2750
2751 try
2752 {
2753 // keep NMI signal source
2754 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2755 std::string service =
2756 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2757 setDbusProperty(
2758 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2759 oemNmiBmcSourceObjPathProp,
2760 sdbusplus::com::intel::Control::server::convertForMessage(
2761 bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002762 // set Enabled property to inform NMI source handling
2763 // to trigger a NMI_OUT BSOD.
2764 // if it's triggered by NMI source property changed,
2765 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2766 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2767 {
2768 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2769 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2770 static_cast<bool>(true));
2771 }
Chen Yugang39736d52019-07-12 16:24:33 +08002772 }
2773 catch (sdbusplus::exception_t& e)
2774 {
2775 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2776 return ipmi::responseResponseError();
2777 }
2778
2779 return ipmi::responseSuccess();
2780}
2781
James Feist63efafa2019-07-24 12:39:21 -07002782namespace dimmOffset
2783{
2784constexpr const char* dimmPower = "DimmPower";
2785constexpr const char* staticCltt = "StaticCltt";
2786constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2787constexpr const char* offsetInterface =
2788 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2789constexpr const char* property = "DimmOffset";
2790
2791}; // namespace dimmOffset
2792
2793ipmi::RspType<>
2794 ipmiOEMSetDimmOffset(uint8_t type,
2795 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2796{
2797 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2798 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2799 {
2800 return ipmi::responseInvalidFieldRequest();
2801 }
2802
2803 if (data.empty())
2804 {
2805 return ipmi::responseInvalidFieldRequest();
2806 }
2807 nlohmann::json json;
2808
2809 std::ifstream jsonStream(dimmOffsetFile);
2810 if (jsonStream.good())
2811 {
2812 json = nlohmann::json::parse(jsonStream, nullptr, false);
2813 if (json.is_discarded())
2814 {
2815 json = nlohmann::json();
2816 }
2817 jsonStream.close();
2818 }
2819
2820 std::string typeName;
2821 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2822 {
2823 typeName = dimmOffset::dimmPower;
2824 }
2825 else
2826 {
2827 typeName = dimmOffset::staticCltt;
2828 }
2829
2830 nlohmann::json& field = json[typeName];
2831
2832 for (const auto& [index, value] : data)
2833 {
2834 field[index] = value;
2835 }
2836
2837 for (nlohmann::json& val : field)
2838 {
2839 if (val == nullptr)
2840 {
2841 val = static_cast<uint8_t>(0);
2842 }
2843 }
2844
2845 std::ofstream output(dimmOffsetFile);
2846 if (!output.good())
2847 {
2848 std::cerr << "Error writing json file\n";
2849 return ipmi::responseResponseError();
2850 }
2851
2852 output << json.dump(4);
2853
2854 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2855 {
2856 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
2857
2858 std::variant<std::vector<uint8_t>> offsets =
2859 field.get<std::vector<uint8_t>>();
2860 auto call = bus->new_method_call(
2861 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
2862 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
2863 try
2864 {
2865 bus->call(call);
2866 }
2867 catch (sdbusplus::exception_t& e)
2868 {
2869 phosphor::logging::log<phosphor::logging::level::ERR>(
2870 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
2871 phosphor::logging::entry("ERR=%s", e.what()));
2872 return ipmi::responseResponseError();
2873 }
2874 }
2875
2876 return ipmi::responseSuccess();
2877}
2878
2879ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
2880{
2881
2882 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2883 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2884 {
2885 return ipmi::responseInvalidFieldRequest();
2886 }
2887
2888 std::ifstream jsonStream(dimmOffsetFile);
2889
2890 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
2891 if (json.is_discarded())
2892 {
2893 std::cerr << "File error in " << dimmOffsetFile << "\n";
2894 return ipmi::responseResponseError();
2895 }
2896
2897 std::string typeName;
2898 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2899 {
2900 typeName = dimmOffset::dimmPower;
2901 }
2902 else
2903 {
2904 typeName = dimmOffset::staticCltt;
2905 }
2906
2907 auto it = json.find(typeName);
2908 if (it == json.end())
2909 {
2910 return ipmi::responseInvalidFieldRequest();
2911 }
2912
2913 if (it->size() <= index)
2914 {
2915 return ipmi::responseInvalidFieldRequest();
2916 }
2917
2918 uint8_t resp = it->at(index).get<uint8_t>();
2919 return ipmi::responseSuccess(resp);
2920}
2921
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08002922namespace boot_options
2923{
2924
2925using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
2926using IpmiValue = uint8_t;
2927constexpr auto ipmiDefault = 0;
2928
2929std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
2930 {0x01, Source::Sources::Network},
2931 {0x02, Source::Sources::Disk},
2932 {0x05, Source::Sources::ExternalMedia},
2933 {0x0f, Source::Sources::RemovableMedia},
2934 {ipmiDefault, Source::Sources::Default}};
2935
2936std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08002937 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08002938
2939std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
2940 {Source::Sources::Network, 0x01},
2941 {Source::Sources::Disk, 0x02},
2942 {Source::Sources::ExternalMedia, 0x05},
2943 {Source::Sources::RemovableMedia, 0x0f},
2944 {Source::Sources::Default, ipmiDefault}};
2945
2946std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08002947 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08002948
2949static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
2950static constexpr auto bootSourceIntf =
2951 "xyz.openbmc_project.Control.Boot.Source";
2952static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
2953static constexpr auto persistentObjPath =
2954 "/xyz/openbmc_project/control/host0/boot";
2955static constexpr auto oneTimePath =
2956 "/xyz/openbmc_project/control/host0/boot/one_time";
2957static constexpr auto bootSourceProp = "BootSource";
2958static constexpr auto bootModeProp = "BootMode";
2959static constexpr auto oneTimeBootEnableProp = "Enabled";
2960static constexpr auto httpBootMode =
2961 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
2962
2963enum class BootOptionParameter : size_t
2964{
2965 setInProgress = 0x0,
2966 bootFlags = 0x5,
2967};
2968static constexpr uint8_t setComplete = 0x0;
2969static constexpr uint8_t setInProgress = 0x1;
2970static uint8_t transferStatus = setComplete;
2971static constexpr uint8_t setParmVersion = 0x01;
2972static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
2973static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
2974static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
2975static constexpr uint8_t httpBoot = 0xd;
2976static constexpr uint8_t bootSourceMask = 0x3c;
2977
2978} // namespace boot_options
2979
2980ipmi::RspType<uint8_t, // version
2981 uint8_t, // param
2982 uint8_t, // data0, dependent on parameter
2983 std::optional<uint8_t> // data1, dependent on parameter
2984 >
2985 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
2986{
2987 using namespace boot_options;
2988 uint8_t bootOption = 0;
2989
2990 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
2991 {
2992 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
2993 std::nullopt);
2994 }
2995
2996 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
2997 {
2998 phosphor::logging::log<phosphor::logging::level::ERR>(
2999 "Unsupported parameter");
3000 return ipmi::responseResponseError();
3001 }
3002
3003 try
3004 {
3005 auto oneTimeEnabled = false;
3006 // read one time Enabled property
3007 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3008 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3009 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3010 enabledIntf, oneTimeBootEnableProp);
3011 oneTimeEnabled = std::get<bool>(variant);
3012
3013 // get BootSource and BootMode properties
3014 // according to oneTimeEnable
3015 auto bootObjPath = oneTimePath;
3016 if (oneTimeEnabled == false)
3017 {
3018 bootObjPath = persistentObjPath;
3019 }
3020
3021 service = getService(*dbus, bootModeIntf, bootObjPath);
3022 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3023 bootModeProp);
3024
3025 auto bootMode =
3026 Mode::convertModesFromString(std::get<std::string>(variant));
3027
3028 service = getService(*dbus, bootSourceIntf, bootObjPath);
3029 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3030 bootSourceProp);
3031
3032 if (std::get<std::string>(variant) == httpBootMode)
3033 {
3034 bootOption = httpBoot;
3035 }
3036 else
3037 {
3038 auto bootSource = Source::convertSourcesFromString(
3039 std::get<std::string>(variant));
3040 bootOption = sourceDbusToIpmi.at(bootSource);
3041 if (Source::Sources::Default == bootSource)
3042 {
3043 bootOption = modeDbusToIpmi.at(bootMode);
3044 }
3045 }
3046
3047 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3048 : setParmBootFlagsValidPermanent;
3049 bootOption <<= 2; // shift for responseconstexpr
3050 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3051 bootOption);
3052 }
3053 catch (sdbusplus::exception_t& e)
3054 {
3055 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3056 return ipmi::responseResponseError();
3057 }
3058}
3059
3060ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3061 std::optional<uint8_t> bootOption)
3062{
3063 using namespace boot_options;
3064 auto oneTimeEnabled = false;
3065
3066 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3067 {
3068 if (bootOption)
3069 {
3070 return ipmi::responseReqDataLenInvalid();
3071 }
3072
3073 if (transferStatus == setInProgress)
3074 {
3075 phosphor::logging::log<phosphor::logging::level::ERR>(
3076 "boot option set in progress!");
3077 return ipmi::responseResponseError();
3078 }
3079
3080 transferStatus = bootParam;
3081 return ipmi::responseSuccess();
3082 }
3083
3084 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3085 {
3086 phosphor::logging::log<phosphor::logging::level::ERR>(
3087 "Unsupported parameter");
3088 return ipmi::responseResponseError();
3089 }
3090
3091 if (!bootOption)
3092 {
3093 return ipmi::responseReqDataLenInvalid();
3094 }
3095
3096 if (((bootOption.value() & bootSourceMask) >> 2) !=
3097 httpBoot) // not http boot, exit
3098 {
3099 phosphor::logging::log<phosphor::logging::level::ERR>(
3100 "wrong boot option parameter!");
3101 return ipmi::responseParmOutOfRange();
3102 }
3103
3104 try
3105 {
3106 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3107 setParmBootFlagsPermanent;
3108
3109 // read one time Enabled property
3110 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3111 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3112 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3113 enabledIntf, oneTimeBootEnableProp);
3114 oneTimeEnabled = std::get<bool>(variant);
3115
3116 /*
3117 * Check if the current boot setting is onetime or permanent, if the
3118 * request in the command is otherwise, then set the "Enabled"
3119 * property in one_time object path to 'True' to indicate onetime
3120 * and 'False' to indicate permanent.
3121 *
3122 * Once the onetime/permanent setting is applied, then the bootMode
3123 * and bootSource is updated for the corresponding object.
3124 */
3125 if (permanent == oneTimeEnabled)
3126 {
3127 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3128 oneTimeBootEnableProp, !permanent);
3129 }
3130
3131 // set BootSource and BootMode properties
3132 // according to oneTimeEnable or persistent
3133 auto bootObjPath = oneTimePath;
3134 if (oneTimeEnabled == false)
3135 {
3136 bootObjPath = persistentObjPath;
3137 }
3138 std::string bootMode =
3139 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3140 std::string bootSource = httpBootMode;
3141
3142 service = getService(*dbus, bootModeIntf, bootObjPath);
3143 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3144 bootMode);
3145
3146 service = getService(*dbus, bootSourceIntf, bootObjPath);
3147 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3148 bootSourceProp, bootSource);
3149 }
3150 catch (sdbusplus::exception_t& e)
3151 {
3152 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3153 return ipmi::responseResponseError();
3154 }
3155
3156 return ipmi::responseSuccess();
3157}
3158
Chen Yugangca12a7b2019-09-03 18:11:44 +08003159ipmi::RspType<> ipmiOemSetBootOptions(uint8_t bootFlag, uint8_t bootParam,
3160 std::optional<uint8_t> bootOption)
3161{
3162 bool oneTimeEnabled = false;
3163 uint8_t bootOptionValue = 0;
3164 static constexpr const uint8_t shiftBits = 2;
3165
3166 if (bootFlag ==
3167 static_cast<uint8_t>(boot_options::BootOptionParameter::setInProgress))
3168 {
3169 if (bootOption)
3170 {
3171 return ipmi::responseReqDataLenInvalid();
3172 }
3173
3174 if (boot_options::transferStatus == boot_options::setInProgress)
3175 {
3176 phosphor::logging::log<phosphor::logging::level::ERR>(
3177 "boot option set in progress!");
3178 return ipmi::responseResponseError();
3179 }
3180
3181 boot_options::transferStatus = bootParam;
3182 return ipmi::responseSuccess();
3183 }
3184
3185 if (bootFlag !=
3186 static_cast<uint8_t>(boot_options::BootOptionParameter::bootFlags))
3187 {
3188 phosphor::logging::log<phosphor::logging::level::ERR>(
3189 "Unsupported parameter");
3190 return ipmi::responseResponseError();
3191 }
3192
3193 if (!bootOption)
3194 {
3195 return ipmi::responseReqDataLenInvalid();
3196 }
3197 bootOptionValue =
3198 (bootOption.value() & boot_options::bootSourceMask) >> shiftBits;
3199
3200 try
3201 {
3202 bool permanent =
3203 (bootParam & boot_options::setParmBootFlagsPermanent) ==
3204 boot_options::setParmBootFlagsPermanent;
3205 auto bootMode = boot_options::Mode::Modes::Regular;
3206 auto bootSource = boot_options::Source::Sources::Default;
3207
3208 // read one time Enabled property
3209 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3210 std::string service = getService(*dbus, boot_options::enabledIntf,
3211 boot_options::oneTimePath);
3212 Value variant = getDbusProperty(
3213 *dbus, service, boot_options::oneTimePath,
3214 boot_options::enabledIntf, boot_options::oneTimeBootEnableProp);
3215 oneTimeEnabled = std::get_if<bool>(&variant);
3216
3217 /*
3218 * Check if the current boot setting is onetime or permanent, if the
3219 * request in the command is otherwise, then set the "Enabled"
3220 * property in one_time object path to 'True' to indicate onetime
3221 * and 'False' to indicate permanent.
3222 *
3223 * Once the onetime/permanent setting is applied, then the bootMode
3224 * and bootSource is updated for the corresponding object.
3225 */
3226 if (permanent == oneTimeEnabled)
3227 {
3228 setDbusProperty(*dbus, service, boot_options::oneTimePath,
3229 boot_options::enabledIntf,
3230 boot_options::oneTimeBootEnableProp, !permanent);
3231 }
3232
3233 // set BootSource and BootMode properties
3234 // according to oneTimeEnable or persistent
3235 auto bootObjPath = boot_options::oneTimePath;
3236 if (oneTimeEnabled == false)
3237 {
3238 bootObjPath = boot_options::persistentObjPath;
3239 }
3240
3241 auto modeItr = boot_options::modeIpmiToDbus.find(bootOptionValue);
3242 auto sourceItr = boot_options::sourceIpmiToDbus.find(bootOptionValue);
3243
3244 if (boot_options::sourceIpmiToDbus.end() != sourceItr)
3245 {
3246 bootSource = sourceItr->second;
3247 }
3248
3249 if (boot_options::modeIpmiToDbus.end() != modeItr)
3250 {
3251 bootMode = modeItr->second;
3252 }
3253
3254 if ((boot_options::modeIpmiToDbus.end() == modeItr) &&
3255 (boot_options::sourceIpmiToDbus.end() == sourceItr))
3256 {
3257 // return error if boot option is not supported
3258 return ipmi::responseInvalidFieldRequest();
3259 }
3260 service = getService(*dbus, boot_options::bootModeIntf, bootObjPath);
3261 setDbusProperty(*dbus, service, bootObjPath, boot_options::bootModeIntf,
3262 boot_options::bootModeProp,
3263 convertForMessage(bootMode));
3264
3265 service = getService(*dbus, boot_options::bootSourceIntf, bootObjPath);
3266 setDbusProperty(
3267 *dbus, service, bootObjPath, boot_options::bootSourceIntf,
3268 boot_options::bootSourceProp, convertForMessage(bootSource));
3269 }
3270 catch (sdbusplus::exception_t& e)
3271 {
3272 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3273 return ipmi::responseResponseError();
3274 }
3275
3276 return ipmi::responseSuccess();
3277}
3278
Jason M. Bills64796042018-10-03 16:51:55 -07003279static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003280{
3281 phosphor::logging::log<phosphor::logging::level::INFO>(
3282 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07003283 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
3284 ipmiOEMWildcard,
3285 PRIVILEGE_USER); // wildcard default handler
3286 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
3287 ipmiOEMWildcard,
3288 PRIVILEGE_USER); // wildcard default handler
3289 ipmiPrintAndRegister(
3290 netfnIntcOEMGeneral,
3291 static_cast<ipmi_cmd_t>(
3292 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
3293 NULL, ipmiOEMGetChassisIdentifier,
3294 PRIVILEGE_USER); // get chassis identifier
3295 ipmiPrintAndRegister(
3296 netfnIntcOEMGeneral,
3297 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
3298 NULL, ipmiOEMSetSystemGUID,
3299 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003300
3301 // <Disable BMC System Reset Action>
3302 ipmi::registerHandler(
3303 ipmi::prioOemBase, netfnIntcOEMGeneral,
3304 static_cast<ipmi::Cmd>(
3305 IPMINetfnIntelOEMGeneralCmd::cmdDisableBMCSystemReset),
3306 ipmi::Privilege::Admin, ipmiOEMDisableBMCSystemReset);
3307 // <Get BMC Reset Disables>
3308 ipmi::registerHandler(
3309 ipmi::prioOemBase, netfnIntcOEMGeneral,
3310 static_cast<ipmi::Cmd>(
3311 IPMINetfnIntelOEMGeneralCmd::cmdGetBMCResetDisables),
3312 ipmi::Privilege::Admin, ipmiOEMGetBMCResetDisables);
3313
Jason M. Bills64796042018-10-03 16:51:55 -07003314 ipmiPrintAndRegister(
3315 netfnIntcOEMGeneral,
3316 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
3317 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
3318 ipmiPrintAndRegister(netfnIntcOEMGeneral,
3319 static_cast<ipmi_cmd_t>(
3320 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
3321 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
3322 ipmiPrintAndRegister(
3323 netfnIntcOEMGeneral,
3324 static_cast<ipmi_cmd_t>(
3325 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
3326 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003327
3328 ipmi::registerHandler(
3329 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
3330 static_cast<ipmi::Cmd>(
3331 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
3332 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
3333
Jason M. Bills64796042018-10-03 16:51:55 -07003334 ipmiPrintAndRegister(
3335 netfnIntcOEMGeneral,
3336 static_cast<ipmi_cmd_t>(
3337 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
3338 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3339 ipmiPrintAndRegister(
3340 netfnIntcOEMGeneral,
3341 static_cast<ipmi_cmd_t>(
3342 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
3343 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303344
3345 ipmi::registerHandler(
3346 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
3347 static_cast<ipmi::Cmd>(
3348 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
3349 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
3350
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303351 ipmi::registerHandler(
3352 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
3353 static_cast<ipmi::Cmd>(
3354 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
3355 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
3356
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003357 // <Get Processor Error Config>
3358 ipmi::registerHandler(
3359 ipmi::prioOemBase, netfnIntcOEMGeneral,
3360 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07003361 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003362 ipmi::Privilege::User, ipmiOEMGetProcessorErrConfig);
3363 // <Set Processor Error Config>
3364 ipmi::registerHandler(
3365 ipmi::prioOemBase, netfnIntcOEMGeneral,
3366 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07003367 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003368 ipmi::Privilege::Admin, ipmiOEMSetProcessorErrConfig);
3369
Yong Li703922d2018-11-06 13:25:31 +08003370 ipmiPrintAndRegister(netfnIntcOEMGeneral,
3371 static_cast<ipmi_cmd_t>(
3372 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
3373 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
3374 ipmiPrintAndRegister(netfnIntcOEMGeneral,
3375 static_cast<ipmi_cmd_t>(
3376 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
3377 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003378
3379 ipmiPrintAndRegister(
3380 netfnIntcOEMGeneral,
3381 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
3382 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
3383
James Feist5b693632019-07-09 09:06:09 -07003384 ipmi::registerHandler(
3385 ipmi::prioOemBase, netfnIntcOEMGeneral,
3386 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
3387 ipmi::Privilege::User, ipmiOEMGetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003388
James Feistacc8a4e2019-04-02 14:23:57 -07003389 ipmi::registerHandler(
3390 ipmi::prioOemBase, netfnIntcOEMGeneral,
3391 static_cast<ipmi::Cmd>(
3392 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
3393 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07003394
James Feistacc8a4e2019-04-02 14:23:57 -07003395 ipmi::registerHandler(
3396 ipmi::prioOemBase, netfnIntcOEMGeneral,
3397 static_cast<ipmi::Cmd>(
3398 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
3399 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
3400
3401 ipmi::registerHandler(
3402 ipmi::prioOemBase, netfnIntcOEMGeneral,
3403 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
3404 ipmi::Privilege::User, ipmiOEMSetFscParameter);
3405
3406 ipmi::registerHandler(
3407 ipmi::prioOemBase, netfnIntcOEMGeneral,
3408 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
3409 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003410
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303411 ipmi::registerHandler(
3412 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
3413 static_cast<ipmi::Cmd>(
3414 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId),
3415 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId);
3416
Chen Yugang39736d52019-07-12 16:24:33 +08003417 ipmi::registerHandler(
3418 ipmi::prioOemBase, netfnIntcOEMGeneral,
3419 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetNmiStatus),
3420 ipmi::Privilege::User, ipmiOEMGetNmiSource);
3421
3422 ipmi::registerHandler(
3423 ipmi::prioOemBase, netfnIntcOEMGeneral,
3424 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus),
3425 ipmi::Privilege::Operator, ipmiOEMSetNmiSource);
3426
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003427 ipmi::registerHandler(
3428 ipmi::prioOemBase, netfnIntcOEMGeneral,
3429 static_cast<ipmi::Cmd>(
3430 IPMINetfnIntelOEMGeneralCmd::cmdGetEfiBootOptions),
3431 ipmi::Privilege::User, ipmiOemGetEfiBootOptions);
3432
3433 ipmi::registerHandler(
3434 ipmi::prioOemBase, netfnIntcOEMGeneral,
3435 static_cast<ipmi::Cmd>(
3436 IPMINetfnIntelOEMGeneralCmd::cmdSetEfiBootOptions),
3437 ipmi::Privilege::Operator, ipmiOemSetEfiBootOptions);
3438
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303439 ipmi::registerHandler(
3440 ipmi::prioOemBase, netfnIntcOEMGeneral,
3441 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetSecurityMode),
3442 Privilege::User, ipmiGetSecurityMode);
3443
3444 ipmi::registerHandler(
3445 ipmi::prioOemBase, netfnIntcOEMGeneral,
3446 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetSecurityMode),
3447 Privilege::Admin, ipmiSetSecurityMode);
3448
Kuiying Wang45f04982018-12-26 09:23:08 +08003449 ipmiPrintAndRegister(
3450 netfnIntcOEMGeneral,
3451 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
3452 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08003453 ipmiPrintAndRegister(
3454 netfnIntcOEMPlatform,
3455 static_cast<ipmi_cmd_t>(
3456 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
3457 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Zhu, Yungebe560b02019-04-21 21:19:21 -04003458 ipmi::registerHandler(
3459 ipmi::prioOemBase, netfnIntcOEMGeneral,
3460 static_cast<ipmi::Cmd>(
3461 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication),
3462 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003463
Cheng C Yang773703a2019-08-15 09:41:11 +08003464 ipmi::registerHandler(
3465 ipmi::prioOemBase, netfnIntcOEMGeneral,
3466 static_cast<ipmi::Cmd>(
3467 IPMINetfnIntelOEMGeneralCmd::cmdSetColdRedundancyConfig),
3468 ipmi::Privilege::User, ipmiOEMSetCRConfig);
3469 ipmi::registerHandler(
3470 ipmi::prioOemBase, netfnIntcOEMGeneral,
3471 static_cast<ipmi::Cmd>(
3472 IPMINetfnIntelOEMGeneralCmd::cmdGetColdRedundancyConfig),
3473 ipmi::Privilege::User, ipmiOEMGetCRConfig);
3474
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003475 registerHandler(prioOemBase, netfn::intel::oemGeneral,
3476 netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
3477 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003478
3479 ipmi::registerHandler(
3480 ipmi::prioOemBase, netfnIntcOEMGeneral,
3481 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetDimmOffset),
3482 ipmi::Privilege::Operator, ipmiOEMSetDimmOffset);
3483
3484 ipmi::registerHandler(
3485 ipmi::prioOemBase, netfnIntcOEMGeneral,
3486 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetDimmOffset),
3487 ipmi::Privilege::Operator, ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003488
3489 ipmi::registerHandler(ipmi::prioOemBase, ipmi::netFnChassis,
3490 ipmi::chassis::cmdSetSystemBootOptions,
3491 ipmi::Privilege::Operator, ipmiOemSetBootOptions);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003492}
3493
3494} // namespace ipmi