blob: 0389c4605c49fbce25616fec00fe113deb7ab31c [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
Chen Yugang7a04f3a2019-10-08 11:12:35 +080022#include <appcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080023#include <array>
James Feist91244a62019-02-19 15:04:54 -080024#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080025#include <boost/process/child.hpp>
26#include <boost/process/io.hpp>
Chen Yugang39736d52019-07-12 16:24:33 +080027#include <com/intel/Control/NMISource/server.hpp>
Yong Li0669d192019-05-06 14:01:46 +080028#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070029#include <commandutils.hpp>
Vernon Mauery4ac799d2019-05-20 15:50:37 -070030#include <filesystem>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080031#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080032#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070033#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070034#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080036#include <phosphor-logging/log.hpp>
Chen Yugang7a04f3a2019-10-08 11:12:35 +080037#include <regex>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080038#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053039#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080040#include <string>
James Feist91244a62019-02-19 15:04:54 -080041#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080042#include <vector>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080043#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
44#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080045#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053046#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080047
48namespace ipmi
49{
Jason M. Bills64796042018-10-03 16:51:55 -070050static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070051
Jason M. Bills64796042018-10-03 16:51:55 -070052static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080053
Suryakanth Sekard509eb92018-11-15 17:44:11 +053054static constexpr auto ethernetIntf =
55 "xyz.openbmc_project.Network.EthernetInterface";
56static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
57static constexpr auto networkService = "xyz.openbmc_project.Network";
58static constexpr auto networkRoot = "/xyz/openbmc_project/network";
59
Chen Yugang39736d52019-07-12 16:24:33 +080060static constexpr const char* oemNmiSourceIntf = "com.intel.Control.NMISource";
61static constexpr const char* oemNmiSourceObjPath =
62 "/com/intel/control/NMISource";
63static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
64static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
65
James Feist63efafa2019-07-24 12:39:21 -070066static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
67
Chen Yugang39736d52019-07-12 16:24:33 +080068enum class NmiSource : uint8_t
69{
70 none = 0,
71 fpBtn = 1,
72 wdPreTimeout = 2,
73 pefMatch = 3,
74 chassisCmd = 4,
75 memoryError = 5,
76 pciSerrPerr = 6,
77 southbridgeNmi = 7,
78 chipsetNmi = 8,
79};
80
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053081static constexpr const char* restricionModeService =
82 "xyz.openbmc_project.RestrictionMode.Manager";
83static constexpr const char* restricionModeBasePath =
84 "/xyz/openbmc_project/control/security/restriction_mode";
85static constexpr const char* restricionModeIntf =
86 "xyz.openbmc_project.Control.Security.RestrictionMode";
87static constexpr const char* restricionModeProperty = "RestrictionMode";
88
89static constexpr const char* specialModeService =
90 "xyz.openbmc_project.SpecialMode";
91static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +053092 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053093static constexpr const char* specialModeIntf =
94 "xyz.openbmc_project.Security.SpecialMode";
95static constexpr const char* specialModeProperty = "SpecialMode";
96
97static constexpr const char* dBusPropertyIntf =
98 "org.freedesktop.DBus.Properties";
99static constexpr const char* dBusPropertyGetMethod = "Get";
100static constexpr const char* dBusPropertySetMethod = "Set";
101
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800102// return code: 0 successful
103int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
104{
105 std::string objpath = "/xyz/openbmc_project/FruDevice";
106 std::string intf = "xyz.openbmc_project.FruDeviceManager";
107 std::string service = getService(bus, intf, objpath);
108 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
109 if (valueTree.empty())
110 {
111 phosphor::logging::log<phosphor::logging::level::ERR>(
112 "No object implements interface",
113 phosphor::logging::entry("INTF=%s", intf.c_str()));
114 return -1;
115 }
116
Jason M. Bills64796042018-10-03 16:51:55 -0700117 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800118 {
119 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
120 if (interface == item.second.end())
121 {
122 continue;
123 }
124
125 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
126 if (property == interface->second.end())
127 {
128 continue;
129 }
130
131 try
132 {
133 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700134 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700135 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800136 {
137 phosphor::logging::log<phosphor::logging::level::ERR>(
138 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800139 return -1;
140 }
Jason M. Bills64796042018-10-03 16:51:55 -0700141 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800142 return 0;
143 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700144 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800145 {
Jason M. Bills64796042018-10-03 16:51:55 -0700146 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800147 return -1;
148 }
149 }
150 return -1;
151}
Jason M. Bills64796042018-10-03 16:51:55 -0700152
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800153ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
154 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700155 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800156{
Jason M. Bills64796042018-10-03 16:51:55 -0700157 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800158 // Status code.
159 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700160 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800161 return rc;
162}
163
164// Returns the Chassis Identifier (serial #)
165ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
166 ipmi_request_t request,
167 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700168 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800169 ipmi_context_t context)
170{
171 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700172 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800173 {
Jason M. Bills64796042018-10-03 16:51:55 -0700174 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800175 return IPMI_CC_REQ_DATA_LEN_INVALID;
176 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700177 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
178 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 {
Jason M. Bills64796042018-10-03 16:51:55 -0700180 *dataLen = serial.size(); // length will never exceed response length
181 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800182 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700183 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800184 return IPMI_CC_OK;
185 }
Jason M. Bills64796042018-10-03 16:51:55 -0700186 *dataLen = 0;
187 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800188}
189
190ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
191 ipmi_request_t request,
192 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700193 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800194{
195 static constexpr size_t safeBufferLength = 50;
196 char buf[safeBufferLength] = {0};
197 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
198
Jason M. Bills64796042018-10-03 16:51:55 -0700199 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800200 {
Jason M. Bills64796042018-10-03 16:51:55 -0700201 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800202 return IPMI_CC_REQ_DATA_LEN_INVALID;
203 }
204
Jason M. Bills64796042018-10-03 16:51:55 -0700205 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800206
207 snprintf(
208 buf, safeBufferLength,
209 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
210 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
211 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
212 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
213 Data->node3, Data->node2, Data->node1);
214 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
215 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800216
217 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
218 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700219 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
220 std::string service = getService(*dbus, intf, objpath);
221 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800222 return IPMI_CC_OK;
223}
224
Jason M. Billsb02bf092019-08-15 13:01:56 -0700225ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
226 uint7_t reserved1)
227{
228 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
229
230 try
231 {
232 auto service =
233 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
234 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
235 bmcResetDisablesIntf, "ResetOnSMI",
236 !disableResetOnSMI);
237 }
238 catch (std::exception& e)
239 {
240 phosphor::logging::log<phosphor::logging::level::ERR>(
241 "Failed to set BMC reset disables",
242 phosphor::logging::entry("EXCEPTION=%s", e.what()));
243 return ipmi::responseUnspecifiedError();
244 }
245
246 return ipmi::responseSuccess();
247}
248
249ipmi::RspType<bool, // disableResetOnSMI
250 uint7_t // reserved
251 >
252 ipmiOEMGetBMCResetDisables()
253{
254 bool disableResetOnSMI = true;
255
256 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
257 try
258 {
259 auto service =
260 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
261 Value variant =
262 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
263 bmcResetDisablesIntf, "ResetOnSMI");
264 disableResetOnSMI = !std::get<bool>(variant);
265 }
266 catch (std::exception& e)
267 {
268 phosphor::logging::log<phosphor::logging::level::ERR>(
269 "Failed to get BMC reset disables",
270 phosphor::logging::entry("EXCEPTION=%s", e.what()));
271 return ipmi::responseUnspecifiedError();
272 }
273
274 return ipmi::responseSuccess(disableResetOnSMI, 0);
275}
276
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800277ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
278 ipmi_request_t request, ipmi_response_t response,
279 ipmi_data_len_t dataLen, ipmi_context_t context)
280{
281 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
282
Jason M. Bills64796042018-10-03 16:51:55 -0700283 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800284 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800285 *dataLen = 0;
286 return IPMI_CC_REQ_DATA_LEN_INVALID;
287 }
Jason M. Bills64796042018-10-03 16:51:55 -0700288 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800289
Vernon Mauery15419dd2019-05-24 09:40:30 -0700290 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
291 std::string service = getService(*dbus, biosIntf, biosObjPath);
292 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
294 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700295 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800296 *dataLen = 1;
297 return IPMI_CC_OK;
298}
299
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800300bool getSwVerInfo(uint8_t& bmcMajor, uint8_t& bmcMinor, uint8_t& meMajor,
301 uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800302{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800303 // step 1 : get BMC Major and Minor numbers from its DBUS property
304 std::optional<MetaRevision> rev{};
305 try
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800306 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800307 std::string version = getActiveSoftwareVersionInfo();
308 rev = convertIntelVersion(version);
309 }
310 catch (const std::exception& e)
311 {
312 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800313 }
314
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800315 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800316 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800317 MetaRevision revision = rev.value();
318 bmcMajor = revision.major;
319
320 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
321 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
322 }
323
324 // step 2 : get ME Major and Minor numbers from its DBUS property
325 try
326 {
327 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
328 std::string service =
329 getService(*dbus, "xyz.openbmc_project.Software.Version",
330 "/xyz/openbmc_project/me_version");
331 Value variant =
332 getDbusProperty(*dbus, service, "/xyz/openbmc_project/me_version",
333 "xyz.openbmc_project.Software.Version", "Version");
334
335 std::string& meString = std::get<std::string>(variant);
336
337 // get ME major number
338 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
339 constexpr size_t matchedPhosphor = 6;
340 std::smatch results;
341 if (std::regex_match(meString, results, pattern1))
342 {
343 if (results.size() == matchedPhosphor)
344 {
345 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
346 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
347 }
348 }
349 }
350 catch (sdbusplus::exception::SdBusError& e)
351 {
352 return false;
353 }
354 return true;
355}
356
357ipmi::RspType<
358 std::variant<std::string,
359 std::tuple<uint8_t, std::array<uint8_t, 2>,
360 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
361 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
362 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
363 ipmiOEMGetDeviceInfo(uint8_t entityType, uint8_t countToRead,
364 uint8_t offset)
365{
366 if (countToRead == 0)
367 {
368 return ipmi::responseReqDataLenInvalid();
369 }
370
371 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
372 {
373 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800374 }
375
376 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800377 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800378 {
379 case OEMDevEntityType::biosId:
380 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700381 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
382 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800383 try
384 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700385 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800386 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700387 std::string& idString = std::get<std::string>(variant);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800388 if (offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800389 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800390 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800391 }
Jason M. Bills64796042018-10-03 16:51:55 -0700392 size_t length = 0;
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800393 if (countToRead > (idString.size() - offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700394 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800395 length = idString.size() - offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700396 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800397 else
398 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800399 length = countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800400 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800401
402 std::string readBuf = {0};
403 readBuf.resize(length);
404 std::copy_n(idString.begin() + offset, length,
405 (readBuf.begin()));
406 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800407 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700408 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800409 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800410 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800411 }
412 }
413 break;
414
415 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800416 {
417 constexpr const size_t verLen = 2;
418 constexpr const size_t verTotalLen = 10;
419 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
420 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
421 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
422 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
423 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
424 // data0/1: BMC version number; data6/7: ME version number
425 // the others: HSC0/1/2 version number, not avaible.
426 if (true != getSwVerInfo(bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
427 {
428 return ipmi::responseUnspecifiedError();
429 }
430 return ipmi::responseSuccess(
431 std::tuple<
432 uint8_t, std::array<uint8_t, verLen>,
433 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
434 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
435 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
436 }
437 break;
438
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800439 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800440 {
441 constexpr const size_t sdrLen = 2;
442 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
443 return ipmi::responseSuccess(
444 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
445 readBuf});
446 }
447 break;
448
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800449 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800450 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800451 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800452}
453
454ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
455 ipmi_request_t request, ipmi_response_t response,
456 ipmi_data_len_t dataLen, ipmi_context_t context)
457{
458 if (*dataLen != 0)
459 {
Jason M. Bills64796042018-10-03 16:51:55 -0700460 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800461 return IPMI_CC_REQ_DATA_LEN_INVALID;
462 }
463
464 *dataLen = 1;
465 uint8_t* res = reinterpret_cast<uint8_t*>(response);
466 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
467 // AIC is available so that BIOS will not timeout repeatly which leads to
468 // slow booting.
469 *res = 0; // Byte1=Count of SlotPosition/FruID records.
470 return IPMI_CC_OK;
471}
472
Jason M. Bills64796042018-10-03 16:51:55 -0700473ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
474 ipmi_request_t request,
475 ipmi_response_t response,
476 ipmi_data_len_t dataLen,
477 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800478{
Jason M. Bills64796042018-10-03 16:51:55 -0700479 GetPowerRestoreDelayRes* resp =
480 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
481
482 if (*dataLen != 0)
483 {
484 *dataLen = 0;
485 return IPMI_CC_REQ_DATA_LEN_INVALID;
486 }
487
Vernon Mauery15419dd2019-05-24 09:40:30 -0700488 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700489 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700490 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700491 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700492 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700493 powerRestoreDelayIntf, powerRestoreDelayProp);
494
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700495 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700496 resp->byteLSB = delay;
497 resp->byteMSB = delay >> 8;
498
499 *dataLen = sizeof(GetPowerRestoreDelayRes);
500
501 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800502}
503
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800504static uint8_t bcdToDec(uint8_t val)
505{
506 return ((val / 16 * 10) + (val % 16));
507}
508
509// Allows an update utility or system BIOS to send the status of an embedded
510// firmware update attempt to the BMC. After received, BMC will create a logging
511// record.
512ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
513 uint8_t majorRevision,
514 uint8_t minorRevision,
515 uint32_t auxInfo)
516{
517 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700518 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800519 target = (target & selEvtTargetMask) >> selEvtTargetShift;
520
521 /* make sure the status is 0, 1, or 2 as per the spec */
522 if (status > 2)
523 {
524 return ipmi::response(ipmi::ccInvalidFieldRequest);
525 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700526 /* make sure the target is 0, 1, 2, or 4 as per the spec */
527 if (target > 4 || target == 3)
528 {
529 return ipmi::response(ipmi::ccInvalidFieldRequest);
530 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800531 /*orignal OEM command is to record OEM SEL.
532 But openbmc does not support OEM SEL, so we redirect it to redfish event
533 logging. */
534 std::string buildInfo;
535 std::string action;
536 switch (FWUpdateTarget(target))
537 {
538 case FWUpdateTarget::targetBMC:
539 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700540 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800541 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
542 " BuildID: " + std::to_string(auxInfo);
543 buildInfo += std::to_string(auxInfo);
544 break;
545 case FWUpdateTarget::targetBIOS:
546 firmware = "BIOS";
547 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700548 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800549 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
550 " minor: " +
551 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
552 " ReleaseNumber: " + // ASCII encoded
553 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
554 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
555 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
556 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
557 break;
558 case FWUpdateTarget::targetME:
559 firmware = "ME";
560 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700561 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800562 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
563 " minor2: " +
564 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
565 " build1: " +
566 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
567 " build2: " +
568 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
569 break;
570 case FWUpdateTarget::targetOEMEWS:
571 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700572 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800573 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
574 " BuildID: " + std::to_string(auxInfo);
575 break;
576 }
577
Jason M. Billsdc249272019-04-03 09:58:40 -0700578 static const std::string openBMCMessageRegistryVersion("0.1");
579 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
580
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800581 switch (status)
582 {
583 case 0x0:
584 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700585 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800586 break;
587 case 0x1:
588 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700589 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800590 break;
591 case 0x2:
592 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700593 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800594 break;
595 default:
596 action = "unknown";
597 break;
598 }
599
Jason M. Billsdc249272019-04-03 09:58:40 -0700600 std::string firmwareInstanceStr =
601 firmware + " instance: " + std::to_string(instance);
602 std::string message("[firmware update] " + firmwareInstanceStr +
603 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800604
605 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700606 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
607 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
608 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800609 return ipmi::responseSuccess();
610}
611
Jason M. Bills64796042018-10-03 16:51:55 -0700612ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
613 ipmi_request_t request,
614 ipmi_response_t response,
615 ipmi_data_len_t dataLen,
616 ipmi_context_t context)
617{
618 SetPowerRestoreDelayReq* data =
619 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
620 uint16_t delay = 0;
621
622 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
623 {
624 *dataLen = 0;
625 return IPMI_CC_REQ_DATA_LEN_INVALID;
626 }
627 delay = data->byteMSB;
628 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700629 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700630 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700631 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
632 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700633 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
634 *dataLen = 0;
635
636 return IPMI_CC_OK;
637}
638
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700639static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700640{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700641 static constexpr const char* cpuPresencePathPrefix =
642 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
643 static constexpr const char* cpuPresenceIntf =
644 "xyz.openbmc_project.Inventory.Item";
645 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
646 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
647 try
Jason M. Bills64796042018-10-03 16:51:55 -0700648 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700649 auto service =
650 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
651
652 ipmi::Value result = ipmi::getDbusProperty(
653 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
654 return std::get<bool>(result);
655 }
656 catch (const std::exception& e)
657 {
658 phosphor::logging::log<phosphor::logging::level::INFO>(
659 "Cannot find processor presence",
660 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
661 return false;
662 }
663}
664
665ipmi::RspType<bool, // CATERR Reset Enabled
666 bool, // ERR2 Reset Enabled
667 uint6_t, // reserved
668 uint8_t, // reserved, returns 0x3F
669 uint6_t, // CPU1 CATERR Count
670 uint2_t, // CPU1 Status
671 uint6_t, // CPU2 CATERR Count
672 uint2_t, // CPU2 Status
673 uint6_t, // CPU3 CATERR Count
674 uint2_t, // CPU3 Status
675 uint6_t, // CPU4 CATERR Count
676 uint2_t, // CPU4 Status
677 uint8_t // Crashdump Count
678 >
679 ipmiOEMGetProcessorErrConfig()
680{
681 bool resetOnCATERR = false;
682 bool resetOnERR2 = false;
683 uint6_t cpu1CATERRCount = 0;
684 uint6_t cpu2CATERRCount = 0;
685 uint6_t cpu3CATERRCount = 0;
686 uint6_t cpu4CATERRCount = 0;
687 uint8_t crashdumpCount = 0;
688 uint2_t cpu1Status =
689 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
690 uint2_t cpu2Status =
691 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
692 uint2_t cpu3Status =
693 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
694 uint2_t cpu4Status =
695 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
696
697 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
698 try
699 {
700 auto service = ipmi::getService(*busp, processorErrConfigIntf,
701 processorErrConfigObjPath);
702
703 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
704 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
705 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
706 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
707 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
708 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
709 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
710 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
711 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
712 }
713 catch (const std::exception& e)
714 {
715 phosphor::logging::log<phosphor::logging::level::ERR>(
716 "Failed to fetch processor error config",
717 phosphor::logging::entry("ERROR=%s", e.what()));
718 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700719 }
720
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700721 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
722 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
723 cpu2Status, cpu3CATERRCount, cpu3Status,
724 cpu4CATERRCount, cpu4Status, crashdumpCount);
725}
Jason M. Bills64796042018-10-03 16:51:55 -0700726
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700727ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
728 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
729 std::optional<bool> clearCPUErrorCount,
730 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
731{
732 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700733
734 try
735 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700736 auto service = ipmi::getService(*busp, processorErrConfigIntf,
737 processorErrConfigObjPath);
738 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
739 processorErrConfigIntf, "ResetOnCATERR",
740 resetOnCATERR);
741 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
742 processorErrConfigIntf, "ResetOnERR2",
743 resetOnERR2);
744 if (clearCPUErrorCount.value_or(false))
745 {
746 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700747 processorErrConfigIntf, "ErrorCountCPU1",
748 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700749 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700750 processorErrConfigIntf, "ErrorCountCPU2",
751 static_cast<uint8_t>(0));
752 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
753 processorErrConfigIntf, "ErrorCountCPU3",
754 static_cast<uint8_t>(0));
755 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
756 processorErrConfigIntf, "ErrorCountCPU4",
757 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700758 }
759 if (clearCrashdumpCount.value_or(false))
760 {
761 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700762 processorErrConfigIntf, "CrashdumpCount",
763 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700764 }
Jason M. Bills64796042018-10-03 16:51:55 -0700765 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700766 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700767 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800768 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700769 "Failed to set processor error config",
770 phosphor::logging::entry("EXCEPTION=%s", e.what()));
771 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700772 }
773
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700774 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700775}
776
Yong Li703922d2018-11-06 13:25:31 +0800777ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
778 ipmi_request_t request,
779 ipmi_response_t response,
780 ipmi_data_len_t dataLen,
781 ipmi_context_t context)
782{
783 GetOEMShutdownPolicyRes* resp =
784 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
785
786 if (*dataLen != 0)
787 {
788 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800789 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800790 *dataLen = 0;
791 return IPMI_CC_REQ_DATA_LEN_INVALID;
792 }
793
794 *dataLen = 0;
795
796 try
797 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700798 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800799 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700800 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
801 Value variant = getDbusProperty(
802 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
803 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800804
805 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
806 convertPolicyFromString(std::get<std::string>(variant)) ==
807 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
808 NoShutdownOnOCOT)
809 {
810 resp->policy = 0;
811 }
812 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
813 convertPolicyFromString(std::get<std::string>(variant)) ==
814 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
815 Policy::ShutdownOnOCOT)
816 {
817 resp->policy = 1;
818 }
819 else
820 {
821 phosphor::logging::log<phosphor::logging::level::ERR>(
822 "oem_set_shutdown_policy: invalid property!",
823 phosphor::logging::entry(
824 "PROP=%s", std::get<std::string>(variant).c_str()));
825 return IPMI_CC_UNSPECIFIED_ERROR;
826 }
Yong Li703922d2018-11-06 13:25:31 +0800827 // TODO needs to check if it is multi-node products,
828 // policy is only supported on node 3/4
829 resp->policySupport = shutdownPolicySupported;
830 }
831 catch (sdbusplus::exception_t& e)
832 {
833 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
834 return IPMI_CC_UNSPECIFIED_ERROR;
835 }
836
837 *dataLen = sizeof(GetOEMShutdownPolicyRes);
838 return IPMI_CC_OK;
839}
840
841ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
842 ipmi_request_t request,
843 ipmi_response_t response,
844 ipmi_data_len_t dataLen,
845 ipmi_context_t context)
846{
847 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800848 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
849 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
850 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800851
852 // TODO needs to check if it is multi-node products,
853 // policy is only supported on node 3/4
854 if (*dataLen != 1)
855 {
856 phosphor::logging::log<phosphor::logging::level::ERR>(
857 "oem_set_shutdown_policy: invalid input len!");
858 *dataLen = 0;
859 return IPMI_CC_REQ_DATA_LEN_INVALID;
860 }
861
862 *dataLen = 0;
863 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
864 {
865 phosphor::logging::log<phosphor::logging::level::ERR>(
866 "oem_set_shutdown_policy: invalid input!");
867 return IPMI_CC_INVALID_FIELD_REQUEST;
868 }
869
Yong Li0669d192019-05-06 14:01:46 +0800870 if (*req == noShutdownOnOCOT)
871 {
872 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
873 Policy::NoShutdownOnOCOT;
874 }
875 else
876 {
877 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
878 Policy::ShutdownOnOCOT;
879 }
880
Yong Li703922d2018-11-06 13:25:31 +0800881 try
882 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700883 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800884 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700885 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800886 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700887 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800888 oemShutdownPolicyObjPathProp,
889 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800890 }
891 catch (sdbusplus::exception_t& e)
892 {
893 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
894 return IPMI_CC_UNSPECIFIED_ERROR;
895 }
896
897 return IPMI_CC_OK;
898}
899
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530900/** @brief implementation for check the DHCP or not in IPv4
901 * @param[in] Channel - Channel number
902 * @returns true or false.
903 */
904static bool isDHCPEnabled(uint8_t Channel)
905{
906 try
907 {
908 auto ethdevice = getChannelName(Channel);
909 if (ethdevice.empty())
910 {
911 return false;
912 }
913 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700914 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530915 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700916 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
917 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530918 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700919 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530920 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
921 {
922 return true;
923 }
924 else
925 {
926 return false;
927 }
928 }
929 catch (sdbusplus::exception_t& e)
930 {
931 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
932 return true;
933 }
934}
935
936/** @brief implementes for check the DHCP or not in IPv6
937 * @param[in] Channel - Channel number
938 * @returns true or false.
939 */
940static bool isDHCPIPv6Enabled(uint8_t Channel)
941{
942
943 try
944 {
945 auto ethdevice = getChannelName(Channel);
946 if (ethdevice.empty())
947 {
948 return false;
949 }
950 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700951 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530952 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700953 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
954 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530955 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700956 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530957 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
958 {
959 return true;
960 }
961 else
962 {
963 return false;
964 }
965 }
966 catch (sdbusplus::exception_t& e)
967 {
968 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
969 return true;
970 }
971}
972
973/** @brief implementes the creating of default new user
974 * @param[in] userName - new username in 16 bytes.
975 * @param[in] userPassword - new password in 20 bytes
976 * @returns ipmi completion code.
977 */
978ipmi::RspType<> ipmiOEMSetUser2Activation(
979 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
980 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
981{
982 bool userState = false;
983 // Check for System Interface not exist and LAN should be static
984 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
985 {
986 ChannelInfo chInfo;
987 try
988 {
989 getChannelInfo(channel, chInfo);
990 }
991 catch (sdbusplus::exception_t& e)
992 {
993 phosphor::logging::log<phosphor::logging::level::ERR>(
994 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
995 phosphor::logging::entry("MSG: %s", e.description()));
996 return ipmi::response(ipmi::ccUnspecifiedError);
997 }
998 if (chInfo.mediumType ==
999 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1000 {
1001 phosphor::logging::log<phosphor::logging::level::ERR>(
1002 "ipmiOEMSetUser2Activation: system interface exist .");
1003 return ipmi::response(ipmi::ccCommandNotAvailable);
1004 }
1005 else
1006 {
1007
1008 if (chInfo.mediumType ==
1009 static_cast<uint8_t>(EChannelMediumType::lan8032))
1010 {
1011 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1012 {
1013 phosphor::logging::log<phosphor::logging::level::ERR>(
1014 "ipmiOEMSetUser2Activation: DHCP enabled .");
1015 return ipmi::response(ipmi::ccCommandNotAvailable);
1016 }
1017 }
1018 }
1019 }
1020 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1021 if (ipmi::ccSuccess ==
1022 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1023 {
1024 if (enabledUsers > 1)
1025 {
1026 phosphor::logging::log<phosphor::logging::level::ERR>(
1027 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1028 return ipmi::response(ipmi::ccCommandNotAvailable);
1029 }
1030 // Check the user 2 is enabled or not
1031 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1032 if (userState == true)
1033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(
1035 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1036 return ipmi::response(ipmi::ccCommandNotAvailable);
1037 }
1038 }
1039 else
1040 {
1041 return ipmi::response(ipmi::ccUnspecifiedError);
1042 }
1043
1044#if BYTE_ORDER == LITTLE_ENDIAN
1045 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1046#endif
1047#if BYTE_ORDER == BIG_ENDIAN
1048 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1049#endif
1050
1051 if (ipmi::ccSuccess ==
1052 ipmiUserSetUserName(ipmiDefaultUserId,
1053 reinterpret_cast<const char*>(userName.data())))
1054 {
1055 if (ipmi::ccSuccess ==
1056 ipmiUserSetUserPassword(
1057 ipmiDefaultUserId,
1058 reinterpret_cast<const char*>(userPassword.data())))
1059 {
1060 if (ipmi::ccSuccess ==
1061 ipmiUserSetPrivilegeAccess(
1062 ipmiDefaultUserId,
1063 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1064 privAccess, true))
1065 {
1066 phosphor::logging::log<phosphor::logging::level::INFO>(
1067 "ipmiOEMSetUser2Activation: user created successfully ");
1068 return ipmi::responseSuccess();
1069 }
1070 }
1071 // we need to delete the default user id which added in this command as
1072 // password / priv setting is failed.
1073 ipmiUserSetUserName(ipmiDefaultUserId, "");
1074 phosphor::logging::log<phosphor::logging::level::ERR>(
1075 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1076 }
1077 else
1078 {
1079 phosphor::logging::log<phosphor::logging::level::ERR>(
1080 "ipmiOEMSetUser2Activation: Setting username failed.");
1081 }
1082
1083 return ipmi::response(ipmi::ccCommandNotAvailable);
1084}
1085
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301086/** @brief implementes setting password for special user
1087 * @param[in] specialUserIndex
1088 * @param[in] userPassword - new password in 20 bytes
1089 * @returns ipmi completion code.
1090 */
1091ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1092 uint8_t specialUserIndex,
1093 std::vector<uint8_t> userPassword)
1094{
1095 ChannelInfo chInfo;
1096 try
1097 {
1098 getChannelInfo(ctx->channel, chInfo);
1099 }
1100 catch (sdbusplus::exception_t& e)
1101 {
1102 phosphor::logging::log<phosphor::logging::level::ERR>(
1103 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1104 phosphor::logging::entry("MSG: %s", e.description()));
1105 return ipmi::responseUnspecifiedError();
1106 }
1107 if (chInfo.mediumType !=
1108 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1109 {
1110 phosphor::logging::log<phosphor::logging::level::ERR>(
1111 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1112 "interface");
1113 return ipmi::responseCommandNotAvailable();
1114 }
1115 if (specialUserIndex != 0)
1116 {
1117 phosphor::logging::log<phosphor::logging::level::ERR>(
1118 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1119 return ipmi::responseParmOutOfRange();
1120 }
1121 constexpr uint8_t minPasswordSizeRequired = 6;
1122 if (userPassword.size() < minPasswordSizeRequired ||
1123 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1124 {
1125 return ipmi::responseReqDataLenInvalid();
1126 }
1127 std::string passwd;
1128 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1129 userPassword.size());
1130 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
1131}
1132
Kuiying Wang45f04982018-12-26 09:23:08 +08001133namespace ledAction
1134{
1135using namespace sdbusplus::xyz::openbmc_project::Led::server;
1136std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
1137 {Physical::Action::Off, 0x00},
1138 {Physical::Action::On, 0x10},
1139 {Physical::Action::Blink, 0x01}};
1140
1141std::map<uint8_t, std::string> offsetObjPath = {
1142 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1143
1144} // namespace ledAction
1145
1146int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1147 const std::string& objPath, uint8_t& state)
1148{
1149 try
1150 {
1151 std::string service = getService(bus, intf, objPath);
1152 Value stateValue =
1153 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001154 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001155 state = ledAction::actionDbusToIpmi.at(
1156 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1157 convertActionFromString(strState));
1158 }
1159 catch (sdbusplus::exception::SdBusError& e)
1160 {
1161 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1162 return -1;
1163 }
1164 return 0;
1165}
1166
1167ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1168 ipmi_request_t request, ipmi_response_t response,
1169 ipmi_data_len_t dataLen, ipmi_context_t context)
1170{
1171 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1172 // LED Status
1173 //[1:0] = Reserved
1174 //[3:2] = Status(Amber)
1175 //[5:4] = Status(Green)
1176 //[7:6] = System Identify
1177 // Status definitions:
1178 // 00b = Off
1179 // 01b = Blink
1180 // 10b = On
1181 // 11b = invalid
1182 if (*dataLen != 0)
1183 {
1184 phosphor::logging::log<phosphor::logging::level::ERR>(
1185 "oem_get_led_status: invalid input len!");
1186 *dataLen = 0;
1187 return IPMI_CC_REQ_DATA_LEN_INVALID;
1188 }
1189
1190 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1191 *resp = 0;
1192 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001193 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001194 for (auto it = ledAction::offsetObjPath.begin();
1195 it != ledAction::offsetObjPath.end(); ++it)
1196 {
1197 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001198 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001199 {
1200 phosphor::logging::log<phosphor::logging::level::ERR>(
1201 "oem_get_led_status: fail to get ID LED status!");
1202 return IPMI_CC_UNSPECIFIED_ERROR;
1203 }
1204 *resp |= state << it->first;
1205 }
1206
1207 *dataLen = sizeof(*resp);
1208 return IPMI_CC_OK;
1209}
1210
Yong Li23737fe2019-02-19 08:49:55 +08001211ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1212 ipmi_request_t request,
1213 ipmi_response_t response,
1214 ipmi_data_len_t dataLen,
1215 ipmi_context_t context)
1216{
1217 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1218 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1219
1220 if (*dataLen == 0)
1221 {
1222 phosphor::logging::log<phosphor::logging::level::ERR>(
1223 "CfgHostSerial: invalid input len!",
1224 phosphor::logging::entry("LEN=%d", *dataLen));
1225 return IPMI_CC_REQ_DATA_LEN_INVALID;
1226 }
1227
1228 switch (req->command)
1229 {
1230 case getHostSerialCfgCmd:
1231 {
1232 if (*dataLen != 1)
1233 {
1234 phosphor::logging::log<phosphor::logging::level::ERR>(
1235 "CfgHostSerial: invalid input len!");
1236 *dataLen = 0;
1237 return IPMI_CC_REQ_DATA_LEN_INVALID;
1238 }
1239
1240 *dataLen = 0;
1241
1242 boost::process::ipstream is;
1243 std::vector<std::string> data;
1244 std::string line;
1245 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1246 boost::process::std_out > is);
1247
1248 while (c1.running() && std::getline(is, line) && !line.empty())
1249 {
1250 data.push_back(line);
1251 }
1252
1253 c1.wait();
1254 if (c1.exit_code())
1255 {
1256 phosphor::logging::log<phosphor::logging::level::ERR>(
1257 "CfgHostSerial:: error on execute",
1258 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1259 // Using the default value
1260 *resp = 0;
1261 }
1262 else
1263 {
1264 if (data.size() != 1)
1265 {
1266 phosphor::logging::log<phosphor::logging::level::ERR>(
1267 "CfgHostSerial:: error on read env");
1268 return IPMI_CC_UNSPECIFIED_ERROR;
1269 }
1270 try
1271 {
1272 unsigned long tmp = std::stoul(data[0]);
1273 if (tmp > std::numeric_limits<uint8_t>::max())
1274 {
1275 throw std::out_of_range("Out of range");
1276 }
1277 *resp = static_cast<uint8_t>(tmp);
1278 }
1279 catch (const std::invalid_argument& e)
1280 {
1281 phosphor::logging::log<phosphor::logging::level::ERR>(
1282 "invalid config ",
1283 phosphor::logging::entry("ERR=%s", e.what()));
1284 return IPMI_CC_UNSPECIFIED_ERROR;
1285 }
1286 catch (const std::out_of_range& e)
1287 {
1288 phosphor::logging::log<phosphor::logging::level::ERR>(
1289 "out_of_range config ",
1290 phosphor::logging::entry("ERR=%s", e.what()));
1291 return IPMI_CC_UNSPECIFIED_ERROR;
1292 }
1293 }
1294
1295 *dataLen = 1;
1296 break;
1297 }
1298 case setHostSerialCfgCmd:
1299 {
1300 if (*dataLen != sizeof(CfgHostSerialReq))
1301 {
1302 phosphor::logging::log<phosphor::logging::level::ERR>(
1303 "CfgHostSerial: invalid input len!");
1304 *dataLen = 0;
1305 return IPMI_CC_REQ_DATA_LEN_INVALID;
1306 }
1307
1308 *dataLen = 0;
1309
1310 if (req->parameter > HostSerialCfgParamMax)
1311 {
1312 phosphor::logging::log<phosphor::logging::level::ERR>(
1313 "CfgHostSerial: invalid input!");
1314 return IPMI_CC_INVALID_FIELD_REQUEST;
1315 }
1316
1317 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1318 std::to_string(req->parameter));
1319
1320 c1.wait();
1321 if (c1.exit_code())
1322 {
1323 phosphor::logging::log<phosphor::logging::level::ERR>(
1324 "CfgHostSerial:: error on execute",
1325 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1326 return IPMI_CC_UNSPECIFIED_ERROR;
1327 }
1328 break;
1329 }
1330 default:
1331 phosphor::logging::log<phosphor::logging::level::ERR>(
1332 "CfgHostSerial: invalid input!");
1333 *dataLen = 0;
1334 return IPMI_CC_INVALID_FIELD_REQUEST;
1335 }
1336
1337 return IPMI_CC_OK;
1338}
1339
James Feist91244a62019-02-19 15:04:54 -08001340constexpr const char* thermalModeInterface =
1341 "xyz.openbmc_project.Control.ThermalMode";
1342constexpr const char* thermalModePath =
1343 "/xyz/openbmc_project/control/thermal_mode";
1344
1345bool getFanProfileInterface(
1346 sdbusplus::bus::bus& bus,
1347 boost::container::flat_map<
1348 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1349{
1350 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1351 "GetAll");
1352 call.append(thermalModeInterface);
1353 try
1354 {
1355 auto data = bus.call(call);
1356 data.read(resp);
1357 }
1358 catch (sdbusplus::exception_t& e)
1359 {
1360 phosphor::logging::log<phosphor::logging::level::ERR>(
1361 "getFanProfileInterface: can't get thermal mode!",
1362 phosphor::logging::entry("ERR=%s", e.what()));
1363 return false;
1364 }
1365 return true;
1366}
1367
1368ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1369 ipmi_request_t request, ipmi_response_t response,
1370 ipmi_data_len_t dataLen, ipmi_context_t context)
1371{
1372
1373 if (*dataLen < 2 || *dataLen > 7)
1374 {
1375 phosphor::logging::log<phosphor::logging::level::ERR>(
1376 "ipmiOEMSetFanConfig: invalid input len!");
1377 *dataLen = 0;
1378 return IPMI_CC_REQ_DATA_LEN_INVALID;
1379 }
1380
1381 // todo: tell bios to only send first 2 bytes
1382
1383 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1384 boost::container::flat_map<
1385 std::string, std::variant<std::vector<std::string>, std::string>>
1386 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001387 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1388 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001389 {
1390 return IPMI_CC_UNSPECIFIED_ERROR;
1391 }
1392
1393 std::vector<std::string>* supported =
1394 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1395 if (supported == nullptr)
1396 {
1397 return IPMI_CC_INVALID_FIELD_REQUEST;
1398 }
1399 std::string mode;
1400 if (req->flags &
1401 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1402 {
1403 bool performanceMode =
1404 (req->flags & (1 << static_cast<uint8_t>(
1405 setFanProfileFlags::performAcousSelect))) > 0;
1406
1407 if (performanceMode)
1408 {
1409
1410 if (std::find(supported->begin(), supported->end(),
1411 "Performance") != supported->end())
1412 {
1413 mode = "Performance";
1414 }
1415 }
1416 else
1417 {
1418
1419 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1420 supported->end())
1421 {
1422 mode = "Acoustic";
1423 }
1424 }
1425 if (mode.empty())
1426 {
1427 return IPMI_CC_INVALID_FIELD_REQUEST;
1428 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001429 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001430 thermalModeInterface, "Current", mode);
1431 }
1432
1433 return IPMI_CC_OK;
1434}
1435
James Feist5b693632019-07-09 09:06:09 -07001436ipmi::RspType<uint8_t, // profile support map
1437 uint8_t, // fan control profile enable
1438 uint8_t, // flags
1439 uint32_t // dimm presence bit map
1440 >
1441 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001442{
James Feist91244a62019-02-19 15:04:54 -08001443 boost::container::flat_map<
1444 std::string, std::variant<std::vector<std::string>, std::string>>
1445 profileData;
1446
Vernon Mauery15419dd2019-05-24 09:40:30 -07001447 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1448 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001449 {
James Feist5b693632019-07-09 09:06:09 -07001450 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001451 }
1452
1453 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1454
1455 if (current == nullptr)
1456 {
1457 phosphor::logging::log<phosphor::logging::level::ERR>(
1458 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001459 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001460 }
1461 bool performance = (*current == "Performance");
1462
James Feist5b693632019-07-09 09:06:09 -07001463 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001464 if (performance)
1465 {
James Feist5b693632019-07-09 09:06:09 -07001466 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001467 }
1468
James Feist5b693632019-07-09 09:06:09 -07001469 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001470}
James Feist5f957ca2019-03-14 15:33:55 -07001471constexpr const char* cfmLimitSettingPath =
1472 "/xyz/openbmc_project/control/cfm_limit";
1473constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001474constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001475constexpr const size_t legacyPCHSensorNumber = 0x22;
1476constexpr const char* exitAirPathName = "Exit_Air";
1477constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001478constexpr const char* pidConfigurationIface =
1479 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001480
James Feist09f6b602019-08-08 11:30:03 -07001481static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001482{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001483 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001484 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001485 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1486 "/xyz/openbmc_project/object_mapper",
1487 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001488
James Feistacc8a4e2019-04-02 14:23:57 -07001489 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001490 std::string path;
1491 GetSubTreeType resp;
1492 try
1493 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001494 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001495 reply.read(resp);
1496 }
1497 catch (sdbusplus::exception_t&)
1498 {
1499 phosphor::logging::log<phosphor::logging::level::ERR>(
1500 "ipmiOEMGetFscParameter: mapper error");
1501 };
James Feist09f6b602019-08-08 11:30:03 -07001502 auto config =
1503 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1504 return pair.first.find(name) != std::string::npos;
1505 });
James Feistfaa4f222019-03-21 16:21:55 -07001506 if (config != resp.end())
1507 {
1508 path = std::move(config->first);
1509 }
1510 return path;
1511}
James Feist5f957ca2019-03-14 15:33:55 -07001512
James Feistacc8a4e2019-04-02 14:23:57 -07001513// flat map to make alphabetical
1514static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1515{
1516 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001517 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001518 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001519 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1520 "/xyz/openbmc_project/object_mapper",
1521 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001522
1523 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1524 GetSubTreeType resp;
1525
1526 try
1527 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001528 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001529 reply.read(resp);
1530 }
1531 catch (sdbusplus::exception_t&)
1532 {
1533 phosphor::logging::log<phosphor::logging::level::ERR>(
1534 "getFanConfigPaths: mapper error");
1535 };
1536 for (const auto& [path, objects] : resp)
1537 {
1538 if (objects.empty())
1539 {
1540 continue; // should be impossible
1541 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001542
1543 try
1544 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001545 ret.emplace(path,
1546 getAllDbusProperties(*dbus, objects[0].first, path,
1547 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001548 }
1549 catch (sdbusplus::exception_t& e)
1550 {
1551 phosphor::logging::log<phosphor::logging::level::ERR>(
1552 "getPidConfigs: can't get DbusProperties!",
1553 phosphor::logging::entry("ERR=%s", e.what()));
1554 }
James Feistacc8a4e2019-04-02 14:23:57 -07001555 }
1556 return ret;
1557}
1558
1559ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1560{
1561 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1562 if (data.empty())
1563 {
1564 return ipmi::responseResponseError();
1565 }
1566 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1567 for (const auto& [_, pid] : data)
1568 {
1569 auto findClass = pid.find("Class");
1570 if (findClass == pid.end())
1571 {
1572 phosphor::logging::log<phosphor::logging::level::ERR>(
1573 "ipmiOEMGetFscParameter: found illegal pid "
1574 "configurations");
1575 return ipmi::responseResponseError();
1576 }
1577 std::string type = std::get<std::string>(findClass->second);
1578 if (type == "fan")
1579 {
1580 auto findOutLimit = pid.find("OutLimitMin");
1581 if (findOutLimit == pid.end())
1582 {
1583 phosphor::logging::log<phosphor::logging::level::ERR>(
1584 "ipmiOEMGetFscParameter: found illegal pid "
1585 "configurations");
1586 return ipmi::responseResponseError();
1587 }
1588 // get the min out of all the offsets
1589 minOffset = std::min(
1590 minOffset,
1591 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1592 }
1593 }
1594 if (minOffset == std::numeric_limits<uint8_t>::max())
1595 {
1596 phosphor::logging::log<phosphor::logging::level::ERR>(
1597 "ipmiOEMGetFscParameter: found no fan configurations!");
1598 return ipmi::responseResponseError();
1599 }
1600
1601 return ipmi::responseSuccess(minOffset);
1602}
1603
1604ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1605{
1606 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1607 if (data.empty())
1608 {
1609
1610 phosphor::logging::log<phosphor::logging::level::ERR>(
1611 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1612 return ipmi::responseResponseError();
1613 }
1614
Vernon Mauery15419dd2019-05-24 09:40:30 -07001615 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001616 bool found = false;
1617 for (const auto& [path, pid] : data)
1618 {
1619 auto findClass = pid.find("Class");
1620 if (findClass == pid.end())
1621 {
1622
1623 phosphor::logging::log<phosphor::logging::level::ERR>(
1624 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1625 "configurations");
1626 return ipmi::responseResponseError();
1627 }
1628 std::string type = std::get<std::string>(findClass->second);
1629 if (type == "fan")
1630 {
1631 auto findOutLimit = pid.find("OutLimitMin");
1632 if (findOutLimit == pid.end())
1633 {
1634
1635 phosphor::logging::log<phosphor::logging::level::ERR>(
1636 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1637 "configurations");
1638 return ipmi::responseResponseError();
1639 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001640 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001641 path, pidConfigurationIface, "OutLimitMin",
1642 static_cast<double>(offset));
1643 found = true;
1644 }
1645 }
1646 if (!found)
1647 {
1648 phosphor::logging::log<phosphor::logging::level::ERR>(
1649 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1650 return ipmi::responseResponseError();
1651 }
1652
1653 return ipmi::responseSuccess();
1654}
1655
1656ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1657 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001658{
1659 constexpr const size_t disableLimiting = 0x0;
1660
Vernon Mauery15419dd2019-05-24 09:40:30 -07001661 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001662 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001663 {
James Feist09f6b602019-08-08 11:30:03 -07001664 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001665 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001666 {
James Feist09f6b602019-08-08 11:30:03 -07001667 pathName = exitAirPathName;
1668 }
1669 else if (param1 == legacyPCHSensorNumber)
1670 {
1671 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001672 }
1673 else
1674 {
James Feistacc8a4e2019-04-02 14:23:57 -07001675 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001676 }
James Feist09f6b602019-08-08 11:30:03 -07001677 std::string path = getConfigPath(pathName);
1678 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1679 pidConfigurationIface, "SetPoint",
1680 static_cast<double>(param2));
1681 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001682 }
James Feistacc8a4e2019-04-02 14:23:57 -07001683 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001684 {
James Feistacc8a4e2019-04-02 14:23:57 -07001685 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001686
1687 // must be greater than 50 based on eps
1688 if (cfm < 50 && cfm != disableLimiting)
1689 {
James Feistacc8a4e2019-04-02 14:23:57 -07001690 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001691 }
1692
1693 try
1694 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001695 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001696 cfmLimitIface, "Limit",
1697 static_cast<double>(cfm));
1698 }
1699 catch (sdbusplus::exception_t& e)
1700 {
1701 phosphor::logging::log<phosphor::logging::level::ERR>(
1702 "ipmiOEMSetFscParameter: can't set cfm setting!",
1703 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001704 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001705 }
James Feistacc8a4e2019-04-02 14:23:57 -07001706 return ipmi::responseSuccess();
1707 }
1708 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1709 {
1710 constexpr const size_t maxDomainCount = 8;
1711 uint8_t requestedDomainMask = param1;
1712 boost::container::flat_map data = getPidConfigs();
1713 if (data.empty())
1714 {
1715
1716 phosphor::logging::log<phosphor::logging::level::ERR>(
1717 "ipmiOEMSetFscParameter: found no pid configurations!");
1718 return ipmi::responseResponseError();
1719 }
1720 size_t count = 0;
1721 for (const auto& [path, pid] : data)
1722 {
1723 auto findClass = pid.find("Class");
1724 if (findClass == pid.end())
1725 {
1726
1727 phosphor::logging::log<phosphor::logging::level::ERR>(
1728 "ipmiOEMSetFscParameter: found illegal pid "
1729 "configurations");
1730 return ipmi::responseResponseError();
1731 }
1732 std::string type = std::get<std::string>(findClass->second);
1733 if (type == "fan")
1734 {
1735 if (requestedDomainMask & (1 << count))
1736 {
1737 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001738 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001739 pidConfigurationIface, "OutLimitMax",
1740 static_cast<double>(param2));
1741 }
1742 count++;
1743 }
1744 }
1745 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001746 }
1747 else
1748 {
1749 // todo other command parts possibly
1750 // tcontrol is handled in peci now
1751 // fan speed offset not implemented yet
1752 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001753 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001754 }
1755}
1756
James Feistacc8a4e2019-04-02 14:23:57 -07001757ipmi::RspType<
1758 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1759 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001760{
James Feist09f6b602019-08-08 11:30:03 -07001761 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001762
Vernon Mauery15419dd2019-05-24 09:40:30 -07001763 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001764 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001765 {
James Feistacc8a4e2019-04-02 14:23:57 -07001766 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001767 {
James Feistacc8a4e2019-04-02 14:23:57 -07001768 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001769 }
1770
James Feist09f6b602019-08-08 11:30:03 -07001771 std::string pathName;
1772
1773 if (*param == legacyExitAirSensorNumber)
1774 {
1775 pathName = exitAirPathName;
1776 }
1777 else if (*param == legacyPCHSensorNumber)
1778 {
1779 pathName = pchPathName;
1780 }
1781 else
James Feistfaa4f222019-03-21 16:21:55 -07001782 {
James Feistacc8a4e2019-04-02 14:23:57 -07001783 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001784 }
James Feist09f6b602019-08-08 11:30:03 -07001785
1786 uint8_t setpoint = legacyDefaultSetpoint;
1787 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001788 if (path.size())
1789 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001790 Value val = ipmi::getDbusProperty(
1791 *dbus, "xyz.openbmc_project.EntityManager", path,
1792 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001793 setpoint = std::floor(std::get<double>(val) + 0.5);
1794 }
1795
1796 // old implementation used to return the "default" and current, we
1797 // don't make the default readily available so just make both the
1798 // same
James Feistfaa4f222019-03-21 16:21:55 -07001799
James Feistacc8a4e2019-04-02 14:23:57 -07001800 return ipmi::responseSuccess(
1801 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001802 }
James Feistacc8a4e2019-04-02 14:23:57 -07001803 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1804 {
1805 constexpr const size_t maxDomainCount = 8;
1806
1807 if (!param)
1808 {
1809 return ipmi::responseReqDataLenInvalid();
1810 }
1811 uint8_t requestedDomain = *param;
1812 if (requestedDomain >= maxDomainCount)
1813 {
1814 return ipmi::responseInvalidFieldRequest();
1815 }
1816
1817 boost::container::flat_map data = getPidConfigs();
1818 if (data.empty())
1819 {
1820 phosphor::logging::log<phosphor::logging::level::ERR>(
1821 "ipmiOEMGetFscParameter: found no pid configurations!");
1822 return ipmi::responseResponseError();
1823 }
1824 size_t count = 0;
1825 for (const auto& [_, pid] : data)
1826 {
1827 auto findClass = pid.find("Class");
1828 if (findClass == pid.end())
1829 {
1830 phosphor::logging::log<phosphor::logging::level::ERR>(
1831 "ipmiOEMGetFscParameter: found illegal pid "
1832 "configurations");
1833 return ipmi::responseResponseError();
1834 }
1835 std::string type = std::get<std::string>(findClass->second);
1836 if (type == "fan")
1837 {
1838 if (requestedDomain == count)
1839 {
1840 auto findOutLimit = pid.find("OutLimitMax");
1841 if (findOutLimit == pid.end())
1842 {
1843 phosphor::logging::log<phosphor::logging::level::ERR>(
1844 "ipmiOEMGetFscParameter: found illegal pid "
1845 "configurations");
1846 return ipmi::responseResponseError();
1847 }
1848
1849 return ipmi::responseSuccess(
1850 static_cast<uint8_t>(std::floor(
1851 std::get<double>(findOutLimit->second) + 0.5)));
1852 }
1853 else
1854 {
1855 count++;
1856 }
1857 }
1858 }
1859
1860 return ipmi::responseInvalidFieldRequest();
1861 }
1862 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001863 {
1864
1865 /*
1866 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001867 previous behavior didn't seem to prevent this, ignore the check for
1868 now.
James Feist5f957ca2019-03-14 15:33:55 -07001869
James Feistacc8a4e2019-04-02 14:23:57 -07001870 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001871 {
1872 phosphor::logging::log<phosphor::logging::level::ERR>(
1873 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001874 return IPMI_CC_REQ_DATA_LEN_INVALID;
1875 }
1876 */
1877 Value cfmLimit;
1878 Value cfmMaximum;
1879 try
1880 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001881 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001882 cfmLimitSettingPath, cfmLimitIface,
1883 "Limit");
1884 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001885 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001886 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1887 }
1888 catch (sdbusplus::exception_t& e)
1889 {
1890 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001891 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001892 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001893 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001894 }
1895
James Feistacc8a4e2019-04-02 14:23:57 -07001896 double cfmMax = std::get<double>(cfmMaximum);
1897 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001898
James Feistacc8a4e2019-04-02 14:23:57 -07001899 cfmLim = std::floor(cfmLim + 0.5);
1900 cfmMax = std::floor(cfmMax + 0.5);
1901 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1902 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001903
James Feistacc8a4e2019-04-02 14:23:57 -07001904 return ipmi::responseSuccess(
1905 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001906 }
James Feistacc8a4e2019-04-02 14:23:57 -07001907
James Feist5f957ca2019-03-14 15:33:55 -07001908 else
1909 {
1910 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001911 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001912 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001913 }
1914}
1915
Cheng C Yang773703a2019-08-15 09:41:11 +08001916using crConfigVariant =
1917 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
1918
1919int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1920 const crConfigVariant& value,
1921 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1922{
1923 boost::system::error_code ec;
1924 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07001925 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08001926 "/xyz/openbmc_project/control/power_supply_redundancy",
1927 "org.freedesktop.DBus.Properties", "Set",
1928 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
1929 if (ec)
1930 {
1931 phosphor::logging::log<phosphor::logging::level::ERR>(
1932 "Failed to set dbus property to cold redundancy");
1933 return -1;
1934 }
1935
1936 return 0;
1937}
1938
1939int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1940 crConfigVariant& value,
1941 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1942{
1943 boost::system::error_code ec;
1944 value = ctx->bus->yield_method_call<crConfigVariant>(
James Feist28c72902019-09-16 10:34:07 -07001945 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08001946 "/xyz/openbmc_project/control/power_supply_redundancy",
1947 "org.freedesktop.DBus.Properties", "Get",
1948 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
1949 if (ec)
1950 {
1951 phosphor::logging::log<phosphor::logging::level::ERR>(
1952 "Failed to get dbus property to cold redundancy");
1953 return -1;
1954 }
1955 return 0;
1956}
1957
1958uint8_t getPSUCount(void)
1959{
1960 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1961 ipmi::Value num;
1962 try
1963 {
1964 num = ipmi::getDbusProperty(
1965 *dbus, "xyz.openbmc_project.PSURedundancy",
1966 "/xyz/openbmc_project/control/power_supply_redundancy",
1967 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
1968 }
1969 catch (sdbusplus::exception_t& e)
1970 {
1971 phosphor::logging::log<phosphor::logging::level::ERR>(
1972 "Failed to get PSUNumber property from dbus interface");
1973 return 0;
1974 }
1975 uint8_t* pNum = std::get_if<uint8_t>(&num);
1976 if (!pNum)
1977 {
1978 phosphor::logging::log<phosphor::logging::level::ERR>(
1979 "Error to get PSU Number");
1980 return 0;
1981 }
1982 return *pNum;
1983}
1984
1985bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
1986{
1987 if (conf.size() < num)
1988 {
1989 phosphor::logging::log<phosphor::logging::level::ERR>(
1990 "Invalid PSU Ranking");
1991 return false;
1992 }
1993 std::set<uint8_t> confSet;
1994 for (uint8_t i = 0; i < num; i++)
1995 {
1996 if (conf[i] > num)
1997 {
1998 phosphor::logging::log<phosphor::logging::level::ERR>(
1999 "PSU Ranking is larger than current PSU number");
2000 return false;
2001 }
2002 confSet.emplace(conf[i]);
2003 }
2004
2005 if (confSet.size() != num)
2006 {
2007 phosphor::logging::log<phosphor::logging::level::ERR>(
2008 "duplicate PSU Ranking");
2009 return false;
2010 }
2011 return true;
2012}
2013
2014enum class crParameter
2015{
2016 crStatus = 0,
2017 crFeature = 1,
2018 rotationFeature = 2,
2019 rotationAlgo = 3,
2020 rotationPeriod = 4,
2021 numOfPSU = 5
2022};
2023
2024constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2025static const constexpr uint32_t oneDay = 0x15180;
2026static const constexpr uint32_t oneMonth = 0xf53700;
2027static const constexpr uint8_t userSpecific = 0x01;
2028static const constexpr uint8_t crSetCompleted = 0;
2029ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2030 uint8_t parameter,
2031 ipmi::message::Payload& payload)
2032{
2033 switch (static_cast<crParameter>(parameter))
2034 {
2035 case crParameter::crFeature:
2036 {
2037 uint8_t param1;
2038 if (payload.unpack(param1) || !payload.fullyUnpacked())
2039 {
2040 return ipmi::responseReqDataLenInvalid();
2041 }
2042 // ColdRedundancy Enable can only be true or flase
2043 if (param1 > 1)
2044 {
2045 return ipmi::responseInvalidFieldRequest();
2046 }
2047 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2048 static_cast<bool>(param1)))
2049 {
2050 return ipmi::responseResponseError();
2051 }
2052 break;
2053 }
2054 case crParameter::rotationFeature:
2055 {
2056 uint8_t param1;
2057 if (payload.unpack(param1) || !payload.fullyUnpacked())
2058 {
2059 return ipmi::responseReqDataLenInvalid();
2060 }
2061 // Rotation Enable can only be true or false
2062 if (param1 > 1)
2063 {
2064 return ipmi::responseInvalidFieldRequest();
2065 }
2066 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2067 {
2068 return ipmi::responseResponseError();
2069 }
2070 break;
2071 }
2072 case crParameter::rotationAlgo:
2073 {
2074 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2075 std::string algoName;
2076 uint8_t param1;
2077 if (payload.unpack(param1))
2078 {
2079 return ipmi::responseReqDataLenInvalid();
2080 }
2081 switch (param1)
2082 {
2083 case 0:
2084 algoName = "xyz.openbmc_project.Control."
2085 "PowerSupplyRedundancy.Algo.bmcSpecific";
2086 break;
2087 case 1:
2088 algoName = "xyz.openbmc_project.Control."
2089 "PowerSupplyRedundancy.Algo.userSpecific";
2090 break;
2091 default:
2092 return ipmi::responseInvalidFieldRequest();
2093 }
2094 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2095 {
2096 return ipmi::responseResponseError();
2097 }
2098
2099 uint8_t numberOfPSU = getPSUCount();
2100 if (!numberOfPSU)
2101 {
2102 return ipmi::responseResponseError();
2103 }
2104 std::vector<uint8_t> rankOrder;
2105
2106 if (param1 == userSpecific)
2107 {
2108 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2109 {
2110 ipmi::responseReqDataLenInvalid();
2111 }
2112 if (rankOrder.size() < numberOfPSU)
2113 {
2114 return ipmi::responseReqDataLenInvalid();
2115 }
2116
2117 if (!validateCRAlgo(rankOrder, numberOfPSU))
2118 {
2119 return ipmi::responseInvalidFieldRequest();
2120 }
2121 }
2122 else
2123 {
2124 if (rankOrder.size() > 0)
2125 {
2126 return ipmi::responseReqDataLenInvalid();
2127 }
2128 for (uint8_t i = 1; i <= numberOfPSU; i++)
2129 {
2130 rankOrder.emplace_back(i);
2131 }
2132 }
2133 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2134 {
2135 return ipmi::responseResponseError();
2136 }
2137 break;
2138 }
2139 case crParameter::rotationPeriod:
2140 {
2141 // Minimum Rotation period is One day (86400 seconds) and Max
2142 // Rotation Period is 6 month (0xf53700 seconds)
2143 uint32_t period;
2144 if (payload.unpack(period) || !payload.fullyUnpacked())
2145 {
2146 return ipmi::responseReqDataLenInvalid();
2147 }
2148 if ((period < oneDay) || (period > oneMonth))
2149 {
2150 return ipmi::responseInvalidFieldRequest();
2151 }
2152 if (setCRConfig(ctx, "PeriodOfRotation", period))
2153 {
2154 return ipmi::responseResponseError();
2155 }
2156 break;
2157 }
2158 default:
2159 {
2160 return ipmi::response(ccParameterNotSupported);
2161 }
2162 }
2163
2164 // TODO Halfwidth needs to set SetInProgress
2165 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002166 std::string("xyz.openbmc_project.Control."
2167 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002168 {
2169 return ipmi::responseResponseError();
2170 }
2171 return ipmi::responseSuccess(crSetCompleted);
2172}
2173
Cheng C Yangf41e3342019-09-10 04:47:23 +08002174ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::array<uint8_t, 5>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002175 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2176{
2177 crConfigVariant value;
2178 switch (static_cast<crParameter>(parameter))
2179 {
2180 case crParameter::crStatus:
2181 {
2182 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2183 {
2184 return ipmi::responseResponseError();
2185 }
2186 std::string* pStatus = std::get_if<std::string>(&value);
2187 if (!pStatus)
2188 {
2189 phosphor::logging::log<phosphor::logging::level::ERR>(
2190 "Error to get ColdRedundancyStatus property");
2191 return ipmi::responseResponseError();
2192 }
2193 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2194 auto status =
2195 server::PowerSupplyRedundancy::convertStatusFromString(
2196 *pStatus);
2197 switch (status)
2198 {
2199 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002200 return ipmi::responseSuccess(parameter,
2201 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002202
2203 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002204 return ipmi::responseSuccess(parameter,
2205 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002206 default:
2207 phosphor::logging::log<phosphor::logging::level::ERR>(
2208 "Error to get valid status");
2209 return ipmi::responseResponseError();
2210 }
2211 }
2212 case crParameter::crFeature:
2213 {
2214 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2215 {
2216 return ipmi::responseResponseError();
2217 }
2218 bool* pResponse = std::get_if<bool>(&value);
2219 if (!pResponse)
2220 {
2221 phosphor::logging::log<phosphor::logging::level::ERR>(
2222 "Error to get ColdRedundancyEnable property");
2223 return ipmi::responseResponseError();
2224 }
2225
Cheng C Yangf41e3342019-09-10 04:47:23 +08002226 return ipmi::responseSuccess(parameter,
2227 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002228 }
2229 case crParameter::rotationFeature:
2230 {
2231 if (getCRConfig(ctx, "RotationEnabled", value))
2232 {
2233 return ipmi::responseResponseError();
2234 }
2235 bool* pResponse = std::get_if<bool>(&value);
2236 if (!pResponse)
2237 {
2238 phosphor::logging::log<phosphor::logging::level::ERR>(
2239 "Error to get RotationEnabled property");
2240 return ipmi::responseResponseError();
2241 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002242 return ipmi::responseSuccess(parameter,
2243 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002244 }
2245 case crParameter::rotationAlgo:
2246 {
2247 if (getCRConfig(ctx, "RotationAlgorithm", value))
2248 {
2249 return ipmi::responseResponseError();
2250 }
2251
2252 std::string* pAlgo = std::get_if<std::string>(&value);
2253 if (!pAlgo)
2254 {
2255 phosphor::logging::log<phosphor::logging::level::ERR>(
2256 "Error to get RotationAlgorithm property");
2257 return ipmi::responseResponseError();
2258 }
2259 std::array<uint8_t, 5> response = {0, 0, 0, 0, 0};
2260 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2261 auto algo =
2262 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
2263 switch (algo)
2264 {
2265 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
2266 response[0] = 0;
2267 break;
2268 case server::PowerSupplyRedundancy::Algo::userSpecific:
2269 response[0] = 1;
2270 break;
2271 default:
2272 phosphor::logging::log<phosphor::logging::level::ERR>(
2273 "Error to get valid algo");
2274 return ipmi::responseResponseError();
2275 }
2276
2277 if (getCRConfig(ctx, "RotationRankOrder", value))
2278 {
2279 return ipmi::responseResponseError();
2280 }
2281 std::vector<uint8_t>* pResponse =
2282 std::get_if<std::vector<uint8_t>>(&value);
2283 if (!pResponse)
2284 {
2285 phosphor::logging::log<phosphor::logging::level::ERR>(
2286 "Error to get RotationRankOrder property");
2287 return ipmi::responseResponseError();
2288 }
2289 if (pResponse->size() + 1 > response.size())
2290 {
2291 phosphor::logging::log<phosphor::logging::level::ERR>(
2292 "Incorrect size of RotationAlgorithm property");
2293 return ipmi::responseResponseError();
2294 }
2295 std::copy(pResponse->begin(), pResponse->end(),
2296 response.begin() + 1);
Cheng C Yangf41e3342019-09-10 04:47:23 +08002297 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002298 }
2299 case crParameter::rotationPeriod:
2300 {
2301 if (getCRConfig(ctx, "PeriodOfRotation", value))
2302 {
2303 return ipmi::responseResponseError();
2304 }
2305 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2306 if (!pResponse)
2307 {
2308 phosphor::logging::log<phosphor::logging::level::ERR>(
2309 "Error to get RotationAlgorithm property");
2310 return ipmi::responseResponseError();
2311 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002312 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002313 }
2314 case crParameter::numOfPSU:
2315 {
2316 uint8_t numberOfPSU = getPSUCount();
2317 if (!numberOfPSU)
2318 {
2319 return ipmi::responseResponseError();
2320 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002321 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002322 }
2323 default:
2324 {
2325 return ipmi::response(ccParameterNotSupported);
2326 }
2327 }
2328}
2329
Zhu, Yungebe560b02019-04-21 21:19:21 -04002330ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2331 uint8_t faultState,
2332 uint8_t faultGroup,
2333 std::array<uint8_t, 8>& ledStateData)
2334{
2335 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2336 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2337 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2338 static const std::array<std::string, maxFaultType> faultNames = {
2339 "faultFan", "faultTemp", "faultPower",
2340 "faultDriveSlot", "faultSoftware", "faultMemory"};
2341 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2342 static constexpr const char* postfixValue = "/value";
2343
2344 constexpr uint8_t maxFaultSource = 0x4;
2345 constexpr uint8_t skipLEDs = 0xFF;
2346 constexpr uint8_t pinSize = 64;
2347 constexpr uint8_t groupSize = 16;
2348
2349 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2350 uint64_t resFIndex = 0;
2351 std::string resFType;
2352 std::string service;
2353 ObjectValueTree valueTree;
2354
2355 // Validate the source, fault type
2356 if ((sourceId >= maxFaultSource) ||
2357 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2358 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2359 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2360 {
2361 return ipmi::responseParmOutOfRange();
2362 }
2363
Vernon Mauery15419dd2019-05-24 09:40:30 -07002364 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002365 try
2366 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002367 service = getService(*dbus, intf, objpath);
2368 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002369 }
2370 catch (const std::exception& e)
2371 {
2372 phosphor::logging::log<phosphor::logging::level::ERR>(
2373 "No object implements interface",
2374 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2375 phosphor::logging::entry("INTF=%s", intf));
2376 return ipmi::responseResponseError();
2377 }
2378
2379 if (valueTree.empty())
2380 {
2381 phosphor::logging::log<phosphor::logging::level::ERR>(
2382 "No object implements interface",
2383 phosphor::logging::entry("INTF=%s", intf));
2384 return ipmi::responseResponseError();
2385 }
2386
2387 for (const auto& item : valueTree)
2388 {
2389 // find LedFault configuration
2390 auto interface =
2391 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2392 if (interface == item.second.end())
2393 {
2394 continue;
2395 }
2396
2397 // find matched fault type: faultMemmory / faultFan
2398 // find LedGpioPins/FaultIndex configuration
2399 auto propertyFaultType = interface->second.find("FaultType");
2400 auto propertyFIndex = interface->second.find("FaultIndex");
2401 auto ledIndex = interface->second.find("LedGpioPins");
2402
2403 if (propertyFaultType == interface->second.end() ||
2404 propertyFIndex == interface->second.end() ||
2405 ledIndex == interface->second.end())
2406 {
2407 continue;
2408 }
2409
2410 try
2411 {
2412 Value valIndex = propertyFIndex->second;
2413 resFIndex = std::get<uint64_t>(valIndex);
2414
2415 Value valFType = propertyFaultType->second;
2416 resFType = std::get<std::string>(valFType);
2417 }
2418 catch (const std::bad_variant_access& e)
2419 {
2420 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2421 return ipmi::responseResponseError();
2422 }
2423 // find the matched requested fault type: faultMemmory or faultFan
2424 if (resFType != faultNames[faultType])
2425 {
2426 continue;
2427 }
2428
2429 // read LedGpioPins data
2430 std::vector<uint64_t> ledgpios;
2431 std::variant<std::vector<uint64_t>> message;
2432
Vernon Mauery15419dd2019-05-24 09:40:30 -07002433 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002434 service.c_str(), (std::string(item.first)).c_str(),
2435 "org.freedesktop.DBus.Properties", "Get");
2436
2437 method.append("xyz.openbmc_project.Configuration.LedFault",
2438 "LedGpioPins");
2439
2440 try
2441 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002442 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002443 reply.read(message);
2444 ledgpios = std::get<std::vector<uint64_t>>(message);
2445 }
2446 catch (std::exception& e)
2447 {
2448 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2449 return ipmi::responseResponseError();
2450 }
2451
2452 // Check the size to be sure it will never overflow on groupSize
2453 if (ledgpios.size() > groupSize)
2454 {
2455 phosphor::logging::log<phosphor::logging::level::ERR>(
2456 "Fault gpio Pins out of range!");
2457 return ipmi::responseParmOutOfRange();
2458 }
2459 // Store data, according to command data bit index order
2460 for (int i = 0; i < ledgpios.size(); i++)
2461 {
2462 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2463 }
2464 }
2465
2466 switch (RemoteFaultType(faultType))
2467 {
2468 case (RemoteFaultType::fan):
2469 case (RemoteFaultType::memory):
2470 {
2471 if (faultGroup == skipLEDs)
2472 {
2473 return ipmi::responseSuccess();
2474 }
2475
2476 uint64_t ledState = 0;
2477 // calculate led state bit filed count, each byte has 8bits
2478 // the maximum bits will be 8 * 8 bits
2479 constexpr uint8_t size = sizeof(ledStateData) * 8;
2480 for (int i = 0; i < sizeof(ledStateData); i++)
2481 {
2482 ledState = (uint64_t)(ledState << 8);
2483 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2484 }
2485
2486 std::bitset<size> ledStateBits(ledState);
2487 std::string gpioValue;
2488 for (int i = 0; i < size; i++)
2489 { // skip invalid value
2490 if (ledFaultPins[i] == 0xFFFF)
2491 {
2492 continue;
2493 }
2494
2495 std::string device = sysGpioPath +
2496 std::to_string(ledFaultPins[i]) +
2497 postfixValue;
2498 std::fstream gpioFile;
2499
2500 gpioFile.open(device, std::ios::out);
2501
2502 if (!gpioFile.good())
2503 {
2504 phosphor::logging::log<phosphor::logging::level::ERR>(
2505 "Not Find Led Gpio Device!",
2506 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2507 return ipmi::responseResponseError();
2508 }
2509 gpioFile << std::to_string(
2510 static_cast<uint8_t>(ledStateBits[i]));
2511 gpioFile.close();
2512 }
2513 break;
2514 }
2515 default:
2516 {
2517 // now only support two fault types
2518 return ipmi::responseParmOutOfRange();
2519 }
2520 }
2521
2522 return ipmi::responseSuccess();
2523}
2524
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302525ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2526{
2527 uint8_t prodId = 0;
2528 try
2529 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002530 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302531 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002532 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302533 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2534 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002535 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302536 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2537 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2538 }
2539 catch (std::exception& e)
2540 {
2541 phosphor::logging::log<phosphor::logging::level::ERR>(
2542 "ipmiOEMReadBoardProductId: Product ID read failed!",
2543 phosphor::logging::entry("ERR=%s", e.what()));
2544 }
2545 return ipmi::responseSuccess(prodId);
2546}
2547
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302548/** @brief implements the get security mode command
2549 * @param ctx - ctx pointer
2550 *
2551 * @returns IPMI completion code with following data
2552 * - restriction mode value - As specified in
2553 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2554 * - special mode value - As specified in
2555 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2556 */
2557ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2558{
2559 namespace securityNameSpace =
2560 sdbusplus::xyz::openbmc_project::Control::Security::server;
2561 uint8_t restrictionModeValue = 0;
2562 uint8_t specialModeValue = 0;
2563
2564 boost::system::error_code ec;
2565 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002566 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302567 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2568 restricionModeProperty);
2569 if (ec)
2570 {
2571 phosphor::logging::log<phosphor::logging::level::ERR>(
2572 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2573 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2574 return ipmi::responseUnspecifiedError();
2575 }
2576 restrictionModeValue = static_cast<uint8_t>(
2577 securityNameSpace::RestrictionMode::convertModesFromString(
2578 std::get<std::string>(varRestrMode)));
2579 auto varSpecialMode = ctx->bus->yield_method_call<std::variant<uint8_t>>(
James Feist28c72902019-09-16 10:34:07 -07002580 ctx->yield, ec, specialModeService, specialModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302581 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2582 specialModeProperty);
2583 if (ec)
2584 {
2585 phosphor::logging::log<phosphor::logging::level::ERR>(
2586 "ipmiGetSecurityMode: failed to get SpecialMode property",
2587 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2588 // fall through, let us not worry about SpecialMode property, which is
2589 // not required in user scenario
2590 }
2591 else
2592 {
2593 specialModeValue = std::get<uint8_t>(varSpecialMode);
2594 }
2595 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2596}
2597
2598/** @brief implements the set security mode command
2599 * Command allows to upgrade the restriction mode and won't allow
2600 * to downgrade from system interface
2601 * @param ctx - ctx pointer
2602 * @param restrictionMode - restriction mode value to be set.
2603 *
2604 * @returns IPMI completion code
2605 */
2606ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
2607 uint8_t restrictionMode)
2608{
2609 namespace securityNameSpace =
2610 sdbusplus::xyz::openbmc_project::Control::Security::server;
2611
2612 ChannelInfo chInfo;
2613 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2614 {
2615 phosphor::logging::log<phosphor::logging::level::ERR>(
2616 "ipmiSetSecurityMode: Failed to get Channel Info",
2617 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2618 return ipmi::responseUnspecifiedError();
2619 }
2620 auto reqMode =
2621 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2622
2623 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2624 (reqMode >
2625 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2626 {
2627 return ipmi::responseInvalidFieldRequest();
2628 }
2629
2630 boost::system::error_code ec;
2631 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002632 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302633 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2634 restricionModeProperty);
2635 if (ec)
2636 {
2637 phosphor::logging::log<phosphor::logging::level::ERR>(
2638 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2639 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2640 return ipmi::responseUnspecifiedError();
2641 }
2642 auto currentRestrictionMode =
2643 securityNameSpace::RestrictionMode::convertModesFromString(
2644 std::get<std::string>(varRestrMode));
2645
2646 if (chInfo.mediumType !=
2647 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2648 currentRestrictionMode > reqMode)
2649 {
2650 phosphor::logging::log<phosphor::logging::level::ERR>(
2651 "ipmiSetSecurityMode - Downgrading security mode not supported "
2652 "through system interface",
2653 phosphor::logging::entry(
2654 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2655 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2656 return ipmi::responseCommandNotAvailable();
2657 }
2658
2659 ec.clear();
2660 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002661 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302662 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2663 restricionModeProperty,
2664 static_cast<std::variant<std::string>>(
2665 securityNameSpace::convertForMessage(reqMode)));
2666
2667 if (ec)
2668 {
2669 phosphor::logging::log<phosphor::logging::level::ERR>(
2670 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2671 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2672 return ipmi::responseUnspecifiedError();
2673 }
2674 return ipmi::responseSuccess();
2675}
2676
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002677ipmi::RspType<uint8_t /* restore status */>
2678 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2679{
2680 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2681
2682 if (clr != expClr)
2683 {
2684 return ipmi::responseInvalidFieldRequest();
2685 }
2686 constexpr uint8_t cmdStatus = 0;
2687 constexpr uint8_t cmdDefaultRestore = 0xaa;
2688 constexpr uint8_t cmdFullRestore = 0xbb;
2689 constexpr uint8_t cmdFormat = 0xcc;
2690
2691 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2692
2693 switch (cmd)
2694 {
2695 case cmdStatus:
2696 break;
2697 case cmdDefaultRestore:
2698 case cmdFullRestore:
2699 case cmdFormat:
2700 {
2701 // write file to rwfs root
2702 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2703 std::ofstream restoreFile(restoreOpFname);
2704 if (!restoreFile)
2705 {
2706 return ipmi::responseUnspecifiedError();
2707 }
2708 restoreFile << value << "\n";
2709 break;
2710 }
2711 default:
2712 return ipmi::responseInvalidFieldRequest();
2713 }
2714
2715 constexpr uint8_t restorePending = 0;
2716 constexpr uint8_t restoreComplete = 1;
2717
2718 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2719 ? restorePending
2720 : restoreComplete;
2721 return ipmi::responseSuccess(restoreStatus);
2722}
2723
Chen Yugang39736d52019-07-12 16:24:33 +08002724ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2725{
2726 uint8_t bmcSource;
2727 namespace nmi = sdbusplus::com::intel::Control::server;
2728
2729 try
2730 {
2731 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2732 std::string service =
2733 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2734 Value variant =
2735 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2736 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2737
2738 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2739 std::get<std::string>(variant)))
2740 {
2741 case nmi::NMISource::BMCSourceSignal::None:
2742 bmcSource = static_cast<uint8_t>(NmiSource::none);
2743 break;
2744 case nmi::NMISource::BMCSourceSignal::FpBtn:
2745 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
2746 break;
2747 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
2748 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
2749 break;
2750 case nmi::NMISource::BMCSourceSignal::PefMatch:
2751 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
2752 break;
2753 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2754 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2755 break;
2756 case nmi::NMISource::BMCSourceSignal::MemoryError:
2757 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2758 break;
2759 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
2760 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
2761 break;
2762 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
2763 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
2764 break;
2765 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
2766 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
2767 break;
2768 default:
2769 phosphor::logging::log<phosphor::logging::level::ERR>(
2770 "NMI source: invalid property!",
2771 phosphor::logging::entry(
2772 "PROP=%s", std::get<std::string>(variant).c_str()));
2773 return ipmi::responseResponseError();
2774 }
2775 }
2776 catch (sdbusplus::exception::SdBusError& e)
2777 {
2778 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2779 return ipmi::responseResponseError();
2780 }
2781
2782 return ipmi::responseSuccess(bmcSource);
2783}
2784
2785ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2786{
2787 namespace nmi = sdbusplus::com::intel::Control::server;
2788
2789 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2790 nmi::NMISource::BMCSourceSignal::None;
2791
2792 switch (NmiSource(sourceId))
2793 {
2794 case NmiSource::none:
2795 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2796 break;
2797 case NmiSource::fpBtn:
2798 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2799 break;
2800 case NmiSource::wdPreTimeout:
2801 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2802 break;
2803 case NmiSource::pefMatch:
2804 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2805 break;
2806 case NmiSource::chassisCmd:
2807 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2808 break;
2809 case NmiSource::memoryError:
2810 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2811 break;
2812 case NmiSource::pciSerrPerr:
2813 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2814 break;
2815 case NmiSource::southbridgeNmi:
2816 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2817 break;
2818 case NmiSource::chipsetNmi:
2819 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2820 break;
2821 default:
2822 phosphor::logging::log<phosphor::logging::level::ERR>(
2823 "NMI source: invalid property!");
2824 return ipmi::responseResponseError();
2825 }
2826
2827 try
2828 {
2829 // keep NMI signal source
2830 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2831 std::string service =
2832 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2833 setDbusProperty(
2834 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2835 oemNmiBmcSourceObjPathProp,
2836 sdbusplus::com::intel::Control::server::convertForMessage(
2837 bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002838 // set Enabled property to inform NMI source handling
2839 // to trigger a NMI_OUT BSOD.
2840 // if it's triggered by NMI source property changed,
2841 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2842 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2843 {
2844 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2845 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2846 static_cast<bool>(true));
2847 }
Chen Yugang39736d52019-07-12 16:24:33 +08002848 }
2849 catch (sdbusplus::exception_t& e)
2850 {
2851 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2852 return ipmi::responseResponseError();
2853 }
2854
2855 return ipmi::responseSuccess();
2856}
2857
James Feist63efafa2019-07-24 12:39:21 -07002858namespace dimmOffset
2859{
2860constexpr const char* dimmPower = "DimmPower";
2861constexpr const char* staticCltt = "StaticCltt";
2862constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2863constexpr const char* offsetInterface =
2864 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2865constexpr const char* property = "DimmOffset";
2866
2867}; // namespace dimmOffset
2868
2869ipmi::RspType<>
2870 ipmiOEMSetDimmOffset(uint8_t type,
2871 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2872{
2873 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2874 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2875 {
2876 return ipmi::responseInvalidFieldRequest();
2877 }
2878
2879 if (data.empty())
2880 {
2881 return ipmi::responseInvalidFieldRequest();
2882 }
2883 nlohmann::json json;
2884
2885 std::ifstream jsonStream(dimmOffsetFile);
2886 if (jsonStream.good())
2887 {
2888 json = nlohmann::json::parse(jsonStream, nullptr, false);
2889 if (json.is_discarded())
2890 {
2891 json = nlohmann::json();
2892 }
2893 jsonStream.close();
2894 }
2895
2896 std::string typeName;
2897 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2898 {
2899 typeName = dimmOffset::dimmPower;
2900 }
2901 else
2902 {
2903 typeName = dimmOffset::staticCltt;
2904 }
2905
2906 nlohmann::json& field = json[typeName];
2907
2908 for (const auto& [index, value] : data)
2909 {
2910 field[index] = value;
2911 }
2912
2913 for (nlohmann::json& val : field)
2914 {
2915 if (val == nullptr)
2916 {
2917 val = static_cast<uint8_t>(0);
2918 }
2919 }
2920
2921 std::ofstream output(dimmOffsetFile);
2922 if (!output.good())
2923 {
2924 std::cerr << "Error writing json file\n";
2925 return ipmi::responseResponseError();
2926 }
2927
2928 output << json.dump(4);
2929
2930 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2931 {
2932 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
2933
2934 std::variant<std::vector<uint8_t>> offsets =
2935 field.get<std::vector<uint8_t>>();
2936 auto call = bus->new_method_call(
2937 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
2938 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
2939 try
2940 {
2941 bus->call(call);
2942 }
2943 catch (sdbusplus::exception_t& e)
2944 {
2945 phosphor::logging::log<phosphor::logging::level::ERR>(
2946 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
2947 phosphor::logging::entry("ERR=%s", e.what()));
2948 return ipmi::responseResponseError();
2949 }
2950 }
2951
2952 return ipmi::responseSuccess();
2953}
2954
2955ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
2956{
2957
2958 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2959 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2960 {
2961 return ipmi::responseInvalidFieldRequest();
2962 }
2963
2964 std::ifstream jsonStream(dimmOffsetFile);
2965
2966 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
2967 if (json.is_discarded())
2968 {
2969 std::cerr << "File error in " << dimmOffsetFile << "\n";
2970 return ipmi::responseResponseError();
2971 }
2972
2973 std::string typeName;
2974 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2975 {
2976 typeName = dimmOffset::dimmPower;
2977 }
2978 else
2979 {
2980 typeName = dimmOffset::staticCltt;
2981 }
2982
2983 auto it = json.find(typeName);
2984 if (it == json.end())
2985 {
2986 return ipmi::responseInvalidFieldRequest();
2987 }
2988
2989 if (it->size() <= index)
2990 {
2991 return ipmi::responseInvalidFieldRequest();
2992 }
2993
2994 uint8_t resp = it->at(index).get<uint8_t>();
2995 return ipmi::responseSuccess(resp);
2996}
2997
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08002998namespace boot_options
2999{
3000
3001using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3002using IpmiValue = uint8_t;
3003constexpr auto ipmiDefault = 0;
3004
3005std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3006 {0x01, Source::Sources::Network},
3007 {0x02, Source::Sources::Disk},
3008 {0x05, Source::Sources::ExternalMedia},
3009 {0x0f, Source::Sources::RemovableMedia},
3010 {ipmiDefault, Source::Sources::Default}};
3011
3012std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003013 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003014
3015std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3016 {Source::Sources::Network, 0x01},
3017 {Source::Sources::Disk, 0x02},
3018 {Source::Sources::ExternalMedia, 0x05},
3019 {Source::Sources::RemovableMedia, 0x0f},
3020 {Source::Sources::Default, ipmiDefault}};
3021
3022std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003023 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003024
3025static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3026static constexpr auto bootSourceIntf =
3027 "xyz.openbmc_project.Control.Boot.Source";
3028static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3029static constexpr auto persistentObjPath =
3030 "/xyz/openbmc_project/control/host0/boot";
3031static constexpr auto oneTimePath =
3032 "/xyz/openbmc_project/control/host0/boot/one_time";
3033static constexpr auto bootSourceProp = "BootSource";
3034static constexpr auto bootModeProp = "BootMode";
3035static constexpr auto oneTimeBootEnableProp = "Enabled";
3036static constexpr auto httpBootMode =
3037 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3038
3039enum class BootOptionParameter : size_t
3040{
3041 setInProgress = 0x0,
3042 bootFlags = 0x5,
3043};
3044static constexpr uint8_t setComplete = 0x0;
3045static constexpr uint8_t setInProgress = 0x1;
3046static uint8_t transferStatus = setComplete;
3047static constexpr uint8_t setParmVersion = 0x01;
3048static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3049static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3050static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3051static constexpr uint8_t httpBoot = 0xd;
3052static constexpr uint8_t bootSourceMask = 0x3c;
3053
3054} // namespace boot_options
3055
3056ipmi::RspType<uint8_t, // version
3057 uint8_t, // param
3058 uint8_t, // data0, dependent on parameter
3059 std::optional<uint8_t> // data1, dependent on parameter
3060 >
3061 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3062{
3063 using namespace boot_options;
3064 uint8_t bootOption = 0;
3065
3066 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3067 {
3068 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3069 std::nullopt);
3070 }
3071
3072 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3073 {
3074 phosphor::logging::log<phosphor::logging::level::ERR>(
3075 "Unsupported parameter");
3076 return ipmi::responseResponseError();
3077 }
3078
3079 try
3080 {
3081 auto oneTimeEnabled = false;
3082 // read one time Enabled property
3083 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3084 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3085 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3086 enabledIntf, oneTimeBootEnableProp);
3087 oneTimeEnabled = std::get<bool>(variant);
3088
3089 // get BootSource and BootMode properties
3090 // according to oneTimeEnable
3091 auto bootObjPath = oneTimePath;
3092 if (oneTimeEnabled == false)
3093 {
3094 bootObjPath = persistentObjPath;
3095 }
3096
3097 service = getService(*dbus, bootModeIntf, bootObjPath);
3098 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3099 bootModeProp);
3100
3101 auto bootMode =
3102 Mode::convertModesFromString(std::get<std::string>(variant));
3103
3104 service = getService(*dbus, bootSourceIntf, bootObjPath);
3105 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3106 bootSourceProp);
3107
3108 if (std::get<std::string>(variant) == httpBootMode)
3109 {
3110 bootOption = httpBoot;
3111 }
3112 else
3113 {
3114 auto bootSource = Source::convertSourcesFromString(
3115 std::get<std::string>(variant));
3116 bootOption = sourceDbusToIpmi.at(bootSource);
3117 if (Source::Sources::Default == bootSource)
3118 {
3119 bootOption = modeDbusToIpmi.at(bootMode);
3120 }
3121 }
3122
3123 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3124 : setParmBootFlagsValidPermanent;
3125 bootOption <<= 2; // shift for responseconstexpr
3126 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3127 bootOption);
3128 }
3129 catch (sdbusplus::exception_t& e)
3130 {
3131 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3132 return ipmi::responseResponseError();
3133 }
3134}
3135
3136ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3137 std::optional<uint8_t> bootOption)
3138{
3139 using namespace boot_options;
3140 auto oneTimeEnabled = false;
3141
3142 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3143 {
3144 if (bootOption)
3145 {
3146 return ipmi::responseReqDataLenInvalid();
3147 }
3148
3149 if (transferStatus == setInProgress)
3150 {
3151 phosphor::logging::log<phosphor::logging::level::ERR>(
3152 "boot option set in progress!");
3153 return ipmi::responseResponseError();
3154 }
3155
3156 transferStatus = bootParam;
3157 return ipmi::responseSuccess();
3158 }
3159
3160 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3161 {
3162 phosphor::logging::log<phosphor::logging::level::ERR>(
3163 "Unsupported parameter");
3164 return ipmi::responseResponseError();
3165 }
3166
3167 if (!bootOption)
3168 {
3169 return ipmi::responseReqDataLenInvalid();
3170 }
3171
3172 if (((bootOption.value() & bootSourceMask) >> 2) !=
3173 httpBoot) // not http boot, exit
3174 {
3175 phosphor::logging::log<phosphor::logging::level::ERR>(
3176 "wrong boot option parameter!");
3177 return ipmi::responseParmOutOfRange();
3178 }
3179
3180 try
3181 {
3182 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3183 setParmBootFlagsPermanent;
3184
3185 // read one time Enabled property
3186 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3187 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3188 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3189 enabledIntf, oneTimeBootEnableProp);
3190 oneTimeEnabled = std::get<bool>(variant);
3191
3192 /*
3193 * Check if the current boot setting is onetime or permanent, if the
3194 * request in the command is otherwise, then set the "Enabled"
3195 * property in one_time object path to 'True' to indicate onetime
3196 * and 'False' to indicate permanent.
3197 *
3198 * Once the onetime/permanent setting is applied, then the bootMode
3199 * and bootSource is updated for the corresponding object.
3200 */
3201 if (permanent == oneTimeEnabled)
3202 {
3203 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3204 oneTimeBootEnableProp, !permanent);
3205 }
3206
3207 // set BootSource and BootMode properties
3208 // according to oneTimeEnable or persistent
3209 auto bootObjPath = oneTimePath;
3210 if (oneTimeEnabled == false)
3211 {
3212 bootObjPath = persistentObjPath;
3213 }
3214 std::string bootMode =
3215 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3216 std::string bootSource = httpBootMode;
3217
3218 service = getService(*dbus, bootModeIntf, bootObjPath);
3219 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3220 bootMode);
3221
3222 service = getService(*dbus, bootSourceIntf, bootObjPath);
3223 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3224 bootSourceProp, bootSource);
3225 }
3226 catch (sdbusplus::exception_t& e)
3227 {
3228 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3229 return ipmi::responseResponseError();
3230 }
3231
3232 return ipmi::responseSuccess();
3233}
3234
Chen Yugangdd6122b2019-09-24 07:44:50 +08003235ipmi::RspType<>
3236 ipmiOemSetBootOptions(uint8_t bootFlag, uint8_t bootParam,
3237 std::optional<uint8_t> bootOption,
3238 std::optional<std::array<uint8_t, 3>> bootResv)
Chen Yugangca12a7b2019-09-03 18:11:44 +08003239{
3240 bool oneTimeEnabled = false;
3241 uint8_t bootOptionValue = 0;
3242 static constexpr const uint8_t shiftBits = 2;
3243
3244 if (bootFlag ==
3245 static_cast<uint8_t>(boot_options::BootOptionParameter::setInProgress))
3246 {
3247 if (bootOption)
3248 {
3249 return ipmi::responseReqDataLenInvalid();
3250 }
3251
Chen Yugangca12a7b2019-09-03 18:11:44 +08003252 boot_options::transferStatus = bootParam;
3253 return ipmi::responseSuccess();
3254 }
3255
3256 if (bootFlag !=
3257 static_cast<uint8_t>(boot_options::BootOptionParameter::bootFlags))
3258 {
3259 phosphor::logging::log<phosphor::logging::level::ERR>(
3260 "Unsupported parameter");
3261 return ipmi::responseResponseError();
3262 }
3263
3264 if (!bootOption)
3265 {
3266 return ipmi::responseReqDataLenInvalid();
3267 }
3268 bootOptionValue =
3269 (bootOption.value() & boot_options::bootSourceMask) >> shiftBits;
3270
3271 try
3272 {
3273 bool permanent =
3274 (bootParam & boot_options::setParmBootFlagsPermanent) ==
3275 boot_options::setParmBootFlagsPermanent;
3276 auto bootMode = boot_options::Mode::Modes::Regular;
3277 auto bootSource = boot_options::Source::Sources::Default;
3278
3279 // read one time Enabled property
3280 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3281 std::string service = getService(*dbus, boot_options::enabledIntf,
3282 boot_options::oneTimePath);
3283 Value variant = getDbusProperty(
3284 *dbus, service, boot_options::oneTimePath,
3285 boot_options::enabledIntf, boot_options::oneTimeBootEnableProp);
3286 oneTimeEnabled = std::get_if<bool>(&variant);
3287
3288 /*
3289 * Check if the current boot setting is onetime or permanent, if the
3290 * request in the command is otherwise, then set the "Enabled"
3291 * property in one_time object path to 'True' to indicate onetime
3292 * and 'False' to indicate permanent.
3293 *
3294 * Once the onetime/permanent setting is applied, then the bootMode
3295 * and bootSource is updated for the corresponding object.
3296 */
3297 if (permanent == oneTimeEnabled)
3298 {
3299 setDbusProperty(*dbus, service, boot_options::oneTimePath,
3300 boot_options::enabledIntf,
3301 boot_options::oneTimeBootEnableProp, !permanent);
3302 }
3303
3304 // set BootSource and BootMode properties
3305 // according to oneTimeEnable or persistent
3306 auto bootObjPath = boot_options::oneTimePath;
3307 if (oneTimeEnabled == false)
3308 {
3309 bootObjPath = boot_options::persistentObjPath;
3310 }
3311
3312 auto modeItr = boot_options::modeIpmiToDbus.find(bootOptionValue);
3313 auto sourceItr = boot_options::sourceIpmiToDbus.find(bootOptionValue);
3314
3315 if (boot_options::sourceIpmiToDbus.end() != sourceItr)
3316 {
3317 bootSource = sourceItr->second;
3318 }
3319
3320 if (boot_options::modeIpmiToDbus.end() != modeItr)
3321 {
3322 bootMode = modeItr->second;
3323 }
3324
3325 if ((boot_options::modeIpmiToDbus.end() == modeItr) &&
3326 (boot_options::sourceIpmiToDbus.end() == sourceItr))
3327 {
3328 // return error if boot option is not supported
3329 return ipmi::responseInvalidFieldRequest();
3330 }
3331 service = getService(*dbus, boot_options::bootModeIntf, bootObjPath);
3332 setDbusProperty(*dbus, service, bootObjPath, boot_options::bootModeIntf,
3333 boot_options::bootModeProp,
3334 convertForMessage(bootMode));
3335
3336 service = getService(*dbus, boot_options::bootSourceIntf, bootObjPath);
3337 setDbusProperty(
3338 *dbus, service, bootObjPath, boot_options::bootSourceIntf,
3339 boot_options::bootSourceProp, convertForMessage(bootSource));
3340 }
3341 catch (sdbusplus::exception_t& e)
3342 {
3343 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3344 return ipmi::responseResponseError();
3345 }
3346
3347 return ipmi::responseSuccess();
3348}
3349
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003350using BasicVariantType =
3351 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3352 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3353 uint16_t, uint8_t, bool>;
3354using PropertyMapType =
3355 boost::container::flat_map<std::string, BasicVariantType>;
3356static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3357 "xyz.openbmc_project.Configuration.PSUPresence"};
3358int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3359 std::vector<uint64_t>& addrTable)
3360{
3361 boost::system::error_code ec;
3362 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3363 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3364 "/xyz/openbmc_project/object_mapper",
3365 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3366 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3367 if (ec)
3368 {
3369 phosphor::logging::log<phosphor::logging::level::ERR>(
3370 "Failed to set dbus property to cold redundancy");
3371 return -1;
3372 }
3373 for (const auto& object : subtree)
3374 {
3375 std::string pathName = object.first;
3376 for (const auto& serviceIface : object.second)
3377 {
3378 std::string serviceName = serviceIface.first;
3379
3380 ec.clear();
3381 PropertyMapType propMap =
3382 ctx->bus->yield_method_call<PropertyMapType>(
3383 ctx->yield, ec, serviceName, pathName,
3384 "org.freedesktop.DBus.Properties", "GetAll",
3385 "xyz.openbmc_project.Configuration.PSUPresence");
3386 if (ec)
3387 {
3388 phosphor::logging::log<phosphor::logging::level::ERR>(
3389 "Failed to set dbus property to cold redundancy");
3390 return -1;
3391 }
3392 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3393 auto psuAddress =
3394 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3395
3396 if (psuBus == nullptr || psuAddress == nullptr)
3397 {
3398 std::cerr << "error finding necessary "
3399 "entry in configuration\n";
3400 return -1;
3401 }
3402 bus = static_cast<uint8_t>(*psuBus);
3403 addrTable = *psuAddress;
3404 return 0;
3405 }
3406 }
3407 return -1;
3408}
3409
3410static const constexpr uint8_t addrOffset = 8;
3411static const constexpr uint8_t psuRevision = 0xd9;
3412static const constexpr uint8_t defaultPSUBus = 7;
3413// Second Minor, Primary Minor, Major
3414static const constexpr size_t verLen = 3;
3415ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3416{
3417 uint8_t bus = defaultPSUBus;
3418 std::vector<uint64_t> addrTable;
3419 std::vector<uint8_t> result;
3420 if (getPSUAddress(ctx, bus, addrTable))
3421 {
3422 std::cerr << "Failed to get PSU bus and address\n";
3423 return ipmi::responseResponseError();
3424 }
3425
3426 for (const auto& slaveAddr : addrTable)
3427 {
3428 std::vector<uint8_t> writeData = {psuRevision};
3429 std::vector<uint8_t> readBuf(verLen);
3430 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3431 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3432
3433 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3434 if (retI2C != ipmi::ccSuccess)
3435 {
3436 for (size_t idx = 0; idx < verLen; idx++)
3437 {
3438 result.emplace_back(0x00);
3439 }
3440 }
3441 else
3442 {
3443 for (const uint8_t& data : readBuf)
3444 {
3445 result.emplace_back(data);
3446 }
3447 }
3448 }
3449
3450 return ipmi::responseSuccess(result);
3451}
3452
Jason M. Bills64796042018-10-03 16:51:55 -07003453static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003454{
3455 phosphor::logging::log<phosphor::logging::level::INFO>(
3456 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003457 ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003458 ipmiOEMWildcard,
3459 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003460
3461 ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003462 ipmiOEMWildcard,
3463 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003464
3465 ipmiPrintAndRegister(intel::netFnGeneral,
3466 intel::general::cmdGetChassisIdentifier, NULL,
3467 ipmiOEMGetChassisIdentifier,
3468 PRIVILEGE_USER); // get chassis identifier
3469
3470 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3471 NULL, ipmiOEMSetSystemGUID,
3472 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003473
3474 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003475 registerHandler(prioOemBase, intel::netFnGeneral,
3476 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3477 ipmiOEMDisableBMCSystemReset);
3478
Jason M. Billsb02bf092019-08-15 13:01:56 -07003479 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003480 registerHandler(prioOemBase, intel::netFnGeneral,
3481 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3482 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003483
Vernon Mauery98bbf692019-09-16 11:14:59 -07003484 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3485 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003486
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003487 registerHandler(prioOemBase, intel::netFnGeneral,
3488 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3489 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003490
Vernon Mauery98bbf692019-09-16 11:14:59 -07003491 ipmiPrintAndRegister(intel::netFnGeneral,
3492 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3493 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303494
Vernon Mauery98bbf692019-09-16 11:14:59 -07003495 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3496 intel::general::cmdSendEmbeddedFWUpdStatus,
3497 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303498
Vernon Mauery98bbf692019-09-16 11:14:59 -07003499 ipmiPrintAndRegister(intel::netFnGeneral,
3500 intel::general::cmdSetPowerRestoreDelay, NULL,
3501 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3502
3503 ipmiPrintAndRegister(intel::netFnGeneral,
3504 intel::general::cmdGetPowerRestoreDelay, NULL,
3505 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3506
3507 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3508 intel::general::cmdSetOEMUser2Activation,
3509 Privilege::Callback, ipmiOEMSetUser2Activation);
3510
3511 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3512 intel::general::cmdSetSpecialUserPassword,
3513 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303514
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003515 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003516 registerHandler(prioOemBase, intel::netFnGeneral,
3517 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3518 ipmiOEMGetProcessorErrConfig);
3519
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003520 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003521 registerHandler(prioOemBase, intel::netFnGeneral,
3522 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3523 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003524
Vernon Mauery98bbf692019-09-16 11:14:59 -07003525 ipmiPrintAndRegister(intel::netFnGeneral,
3526 intel::general::cmdSetShutdownPolicy, NULL,
3527 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003528
Vernon Mauery98bbf692019-09-16 11:14:59 -07003529 ipmiPrintAndRegister(intel::netFnGeneral,
3530 intel::general::cmdGetShutdownPolicy, NULL,
3531 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003532
Vernon Mauery98bbf692019-09-16 11:14:59 -07003533 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetFanConfig,
3534 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
James Feist91244a62019-02-19 15:04:54 -08003535
Vernon Mauery98bbf692019-09-16 11:14:59 -07003536 registerHandler(prioOemBase, intel::netFnGeneral,
3537 intel::general::cmdGetFanConfig, Privilege::User,
3538 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003539
Vernon Mauery98bbf692019-09-16 11:14:59 -07003540 registerHandler(prioOemBase, intel::netFnGeneral,
3541 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3542 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003543
Vernon Mauery98bbf692019-09-16 11:14:59 -07003544 registerHandler(prioOemBase, intel::netFnGeneral,
3545 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3546 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003547
Vernon Mauery98bbf692019-09-16 11:14:59 -07003548 registerHandler(prioOemBase, intel::netFnGeneral,
3549 intel::general::cmdSetFscParameter, Privilege::User,
3550 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003551
Vernon Mauery98bbf692019-09-16 11:14:59 -07003552 registerHandler(prioOemBase, intel::netFnGeneral,
3553 intel::general::cmdGetFscParameter, Privilege::User,
3554 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303555
Vernon Mauery98bbf692019-09-16 11:14:59 -07003556 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3557 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3558 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003559
Vernon Mauery98bbf692019-09-16 11:14:59 -07003560 registerHandler(prioOemBase, intel::netFnGeneral,
3561 intel::general::cmdGetNmiStatus, Privilege::User,
3562 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003563
Vernon Mauery98bbf692019-09-16 11:14:59 -07003564 registerHandler(prioOemBase, intel::netFnGeneral,
3565 intel::general::cmdSetNmiStatus, Privilege::Operator,
3566 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003567
Vernon Mauery98bbf692019-09-16 11:14:59 -07003568 registerHandler(prioOemBase, intel::netFnGeneral,
3569 intel::general::cmdGetEfiBootOptions, Privilege::User,
3570 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003571
Vernon Mauery98bbf692019-09-16 11:14:59 -07003572 registerHandler(prioOemBase, intel::netFnGeneral,
3573 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3574 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303575
Vernon Mauery98bbf692019-09-16 11:14:59 -07003576 registerHandler(prioOemBase, intel::netFnGeneral,
3577 intel::general::cmdGetSecurityMode, Privilege::User,
3578 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303579
Vernon Mauery98bbf692019-09-16 11:14:59 -07003580 registerHandler(prioOemBase, intel::netFnGeneral,
3581 intel::general::cmdSetSecurityMode, Privilege::Admin,
3582 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003583
Vernon Mauery98bbf692019-09-16 11:14:59 -07003584 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3585 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003586
Vernon Mauery98bbf692019-09-16 11:14:59 -07003587 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3588 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3589 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3590
3591 registerHandler(prioOemBase, intel::netFnGeneral,
3592 intel::general::cmdSetFaultIndication, Privilege::Operator,
3593 ipmiOEMSetFaultIndication);
3594
3595 registerHandler(prioOemBase, intel::netFnGeneral,
3596 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3597 ipmiOEMSetCRConfig);
3598
3599 registerHandler(prioOemBase, intel::netFnGeneral,
3600 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3601 ipmiOEMGetCRConfig);
3602
3603 registerHandler(prioOemBase, intel::netFnGeneral,
3604 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003605 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003606
Vernon Mauery98bbf692019-09-16 11:14:59 -07003607 registerHandler(prioOemBase, intel::netFnGeneral,
3608 intel::general::cmdSetDimmOffset, Privilege::Operator,
3609 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003610
Vernon Mauery98bbf692019-09-16 11:14:59 -07003611 registerHandler(prioOemBase, intel::netFnGeneral,
3612 intel::general::cmdGetDimmOffset, Privilege::Operator,
3613 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003614
Vernon Mauery98bbf692019-09-16 11:14:59 -07003615 registerHandler(prioOemBase, netFnChassis, chassis::cmdSetSystemBootOptions,
3616 Privilege::Operator, ipmiOemSetBootOptions);
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003617
3618 registerHandler(prioOemBase, intel::netFnGeneral,
3619 intel::general::cmdGetPSUVersion, Privilege::User,
3620 ipmiOEMGetPSUVersion);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003621}
3622
3623} // namespace ipmi