blob: 9e7e84114c34ae5823ab9f9fdb5ad5b0fb9df471 [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 }
Yong Li83315132019-10-23 17:42:24 +08002112 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002113 {
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
Yong Li83315132019-10-23 17:42:24 +08002174ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
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 }
Yong Li83315132019-10-23 17:42:24 +08002259 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002260 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2261 auto algo =
2262 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002263
Cheng C Yang773703a2019-08-15 09:41:11 +08002264 switch (algo)
2265 {
2266 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002267 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002268 break;
2269 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002270 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002271 break;
2272 default:
2273 phosphor::logging::log<phosphor::logging::level::ERR>(
2274 "Error to get valid algo");
2275 return ipmi::responseResponseError();
2276 }
2277
2278 if (getCRConfig(ctx, "RotationRankOrder", value))
2279 {
2280 return ipmi::responseResponseError();
2281 }
2282 std::vector<uint8_t>* pResponse =
2283 std::get_if<std::vector<uint8_t>>(&value);
2284 if (!pResponse)
2285 {
2286 phosphor::logging::log<phosphor::logging::level::ERR>(
2287 "Error to get RotationRankOrder property");
2288 return ipmi::responseResponseError();
2289 }
Yong Li83315132019-10-23 17:42:24 +08002290
Cheng C Yang773703a2019-08-15 09:41:11 +08002291 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002292 std::back_inserter(response));
2293
Cheng C Yangf41e3342019-09-10 04:47:23 +08002294 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002295 }
2296 case crParameter::rotationPeriod:
2297 {
2298 if (getCRConfig(ctx, "PeriodOfRotation", value))
2299 {
2300 return ipmi::responseResponseError();
2301 }
2302 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2303 if (!pResponse)
2304 {
2305 phosphor::logging::log<phosphor::logging::level::ERR>(
2306 "Error to get RotationAlgorithm property");
2307 return ipmi::responseResponseError();
2308 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002309 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002310 }
2311 case crParameter::numOfPSU:
2312 {
2313 uint8_t numberOfPSU = getPSUCount();
2314 if (!numberOfPSU)
2315 {
2316 return ipmi::responseResponseError();
2317 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002318 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002319 }
2320 default:
2321 {
2322 return ipmi::response(ccParameterNotSupported);
2323 }
2324 }
2325}
2326
Zhu, Yungebe560b02019-04-21 21:19:21 -04002327ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2328 uint8_t faultState,
2329 uint8_t faultGroup,
2330 std::array<uint8_t, 8>& ledStateData)
2331{
2332 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2333 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2334 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2335 static const std::array<std::string, maxFaultType> faultNames = {
2336 "faultFan", "faultTemp", "faultPower",
2337 "faultDriveSlot", "faultSoftware", "faultMemory"};
2338 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2339 static constexpr const char* postfixValue = "/value";
2340
2341 constexpr uint8_t maxFaultSource = 0x4;
2342 constexpr uint8_t skipLEDs = 0xFF;
2343 constexpr uint8_t pinSize = 64;
2344 constexpr uint8_t groupSize = 16;
2345
2346 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2347 uint64_t resFIndex = 0;
2348 std::string resFType;
2349 std::string service;
2350 ObjectValueTree valueTree;
2351
2352 // Validate the source, fault type
2353 if ((sourceId >= maxFaultSource) ||
2354 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2355 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2356 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2357 {
2358 return ipmi::responseParmOutOfRange();
2359 }
2360
Vernon Mauery15419dd2019-05-24 09:40:30 -07002361 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002362 try
2363 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002364 service = getService(*dbus, intf, objpath);
2365 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002366 }
2367 catch (const std::exception& e)
2368 {
2369 phosphor::logging::log<phosphor::logging::level::ERR>(
2370 "No object implements interface",
2371 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2372 phosphor::logging::entry("INTF=%s", intf));
2373 return ipmi::responseResponseError();
2374 }
2375
2376 if (valueTree.empty())
2377 {
2378 phosphor::logging::log<phosphor::logging::level::ERR>(
2379 "No object implements interface",
2380 phosphor::logging::entry("INTF=%s", intf));
2381 return ipmi::responseResponseError();
2382 }
2383
2384 for (const auto& item : valueTree)
2385 {
2386 // find LedFault configuration
2387 auto interface =
2388 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2389 if (interface == item.second.end())
2390 {
2391 continue;
2392 }
2393
2394 // find matched fault type: faultMemmory / faultFan
2395 // find LedGpioPins/FaultIndex configuration
2396 auto propertyFaultType = interface->second.find("FaultType");
2397 auto propertyFIndex = interface->second.find("FaultIndex");
2398 auto ledIndex = interface->second.find("LedGpioPins");
2399
2400 if (propertyFaultType == interface->second.end() ||
2401 propertyFIndex == interface->second.end() ||
2402 ledIndex == interface->second.end())
2403 {
2404 continue;
2405 }
2406
2407 try
2408 {
2409 Value valIndex = propertyFIndex->second;
2410 resFIndex = std::get<uint64_t>(valIndex);
2411
2412 Value valFType = propertyFaultType->second;
2413 resFType = std::get<std::string>(valFType);
2414 }
2415 catch (const std::bad_variant_access& e)
2416 {
2417 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2418 return ipmi::responseResponseError();
2419 }
2420 // find the matched requested fault type: faultMemmory or faultFan
2421 if (resFType != faultNames[faultType])
2422 {
2423 continue;
2424 }
2425
2426 // read LedGpioPins data
2427 std::vector<uint64_t> ledgpios;
2428 std::variant<std::vector<uint64_t>> message;
2429
Vernon Mauery15419dd2019-05-24 09:40:30 -07002430 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002431 service.c_str(), (std::string(item.first)).c_str(),
2432 "org.freedesktop.DBus.Properties", "Get");
2433
2434 method.append("xyz.openbmc_project.Configuration.LedFault",
2435 "LedGpioPins");
2436
2437 try
2438 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002439 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002440 reply.read(message);
2441 ledgpios = std::get<std::vector<uint64_t>>(message);
2442 }
2443 catch (std::exception& e)
2444 {
2445 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2446 return ipmi::responseResponseError();
2447 }
2448
2449 // Check the size to be sure it will never overflow on groupSize
2450 if (ledgpios.size() > groupSize)
2451 {
2452 phosphor::logging::log<phosphor::logging::level::ERR>(
2453 "Fault gpio Pins out of range!");
2454 return ipmi::responseParmOutOfRange();
2455 }
2456 // Store data, according to command data bit index order
2457 for (int i = 0; i < ledgpios.size(); i++)
2458 {
2459 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2460 }
2461 }
2462
2463 switch (RemoteFaultType(faultType))
2464 {
2465 case (RemoteFaultType::fan):
2466 case (RemoteFaultType::memory):
2467 {
2468 if (faultGroup == skipLEDs)
2469 {
2470 return ipmi::responseSuccess();
2471 }
2472
2473 uint64_t ledState = 0;
2474 // calculate led state bit filed count, each byte has 8bits
2475 // the maximum bits will be 8 * 8 bits
2476 constexpr uint8_t size = sizeof(ledStateData) * 8;
2477 for (int i = 0; i < sizeof(ledStateData); i++)
2478 {
2479 ledState = (uint64_t)(ledState << 8);
2480 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2481 }
2482
2483 std::bitset<size> ledStateBits(ledState);
2484 std::string gpioValue;
2485 for (int i = 0; i < size; i++)
2486 { // skip invalid value
2487 if (ledFaultPins[i] == 0xFFFF)
2488 {
2489 continue;
2490 }
2491
2492 std::string device = sysGpioPath +
2493 std::to_string(ledFaultPins[i]) +
2494 postfixValue;
2495 std::fstream gpioFile;
2496
2497 gpioFile.open(device, std::ios::out);
2498
2499 if (!gpioFile.good())
2500 {
2501 phosphor::logging::log<phosphor::logging::level::ERR>(
2502 "Not Find Led Gpio Device!",
2503 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2504 return ipmi::responseResponseError();
2505 }
2506 gpioFile << std::to_string(
2507 static_cast<uint8_t>(ledStateBits[i]));
2508 gpioFile.close();
2509 }
2510 break;
2511 }
2512 default:
2513 {
2514 // now only support two fault types
2515 return ipmi::responseParmOutOfRange();
2516 }
2517 }
2518
2519 return ipmi::responseSuccess();
2520}
2521
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302522ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2523{
2524 uint8_t prodId = 0;
2525 try
2526 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002527 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302528 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002529 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302530 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2531 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002532 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302533 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2534 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2535 }
2536 catch (std::exception& e)
2537 {
2538 phosphor::logging::log<phosphor::logging::level::ERR>(
2539 "ipmiOEMReadBoardProductId: Product ID read failed!",
2540 phosphor::logging::entry("ERR=%s", e.what()));
2541 }
2542 return ipmi::responseSuccess(prodId);
2543}
2544
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302545/** @brief implements the get security mode command
2546 * @param ctx - ctx pointer
2547 *
2548 * @returns IPMI completion code with following data
2549 * - restriction mode value - As specified in
2550 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2551 * - special mode value - As specified in
2552 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2553 */
2554ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2555{
2556 namespace securityNameSpace =
2557 sdbusplus::xyz::openbmc_project::Control::Security::server;
2558 uint8_t restrictionModeValue = 0;
2559 uint8_t specialModeValue = 0;
2560
2561 boost::system::error_code ec;
2562 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002563 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302564 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2565 restricionModeProperty);
2566 if (ec)
2567 {
2568 phosphor::logging::log<phosphor::logging::level::ERR>(
2569 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2570 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2571 return ipmi::responseUnspecifiedError();
2572 }
2573 restrictionModeValue = static_cast<uint8_t>(
2574 securityNameSpace::RestrictionMode::convertModesFromString(
2575 std::get<std::string>(varRestrMode)));
2576 auto varSpecialMode = ctx->bus->yield_method_call<std::variant<uint8_t>>(
James Feist28c72902019-09-16 10:34:07 -07002577 ctx->yield, ec, specialModeService, specialModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302578 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2579 specialModeProperty);
2580 if (ec)
2581 {
2582 phosphor::logging::log<phosphor::logging::level::ERR>(
2583 "ipmiGetSecurityMode: failed to get SpecialMode property",
2584 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2585 // fall through, let us not worry about SpecialMode property, which is
2586 // not required in user scenario
2587 }
2588 else
2589 {
2590 specialModeValue = std::get<uint8_t>(varSpecialMode);
2591 }
2592 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2593}
2594
2595/** @brief implements the set security mode command
2596 * Command allows to upgrade the restriction mode and won't allow
2597 * to downgrade from system interface
2598 * @param ctx - ctx pointer
2599 * @param restrictionMode - restriction mode value to be set.
2600 *
2601 * @returns IPMI completion code
2602 */
2603ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
2604 uint8_t restrictionMode)
2605{
2606 namespace securityNameSpace =
2607 sdbusplus::xyz::openbmc_project::Control::Security::server;
2608
2609 ChannelInfo chInfo;
2610 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2611 {
2612 phosphor::logging::log<phosphor::logging::level::ERR>(
2613 "ipmiSetSecurityMode: Failed to get Channel Info",
2614 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2615 return ipmi::responseUnspecifiedError();
2616 }
2617 auto reqMode =
2618 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2619
2620 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2621 (reqMode >
2622 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2623 {
2624 return ipmi::responseInvalidFieldRequest();
2625 }
2626
2627 boost::system::error_code ec;
2628 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002629 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302630 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2631 restricionModeProperty);
2632 if (ec)
2633 {
2634 phosphor::logging::log<phosphor::logging::level::ERR>(
2635 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2636 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2637 return ipmi::responseUnspecifiedError();
2638 }
2639 auto currentRestrictionMode =
2640 securityNameSpace::RestrictionMode::convertModesFromString(
2641 std::get<std::string>(varRestrMode));
2642
2643 if (chInfo.mediumType !=
2644 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2645 currentRestrictionMode > reqMode)
2646 {
2647 phosphor::logging::log<phosphor::logging::level::ERR>(
2648 "ipmiSetSecurityMode - Downgrading security mode not supported "
2649 "through system interface",
2650 phosphor::logging::entry(
2651 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2652 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2653 return ipmi::responseCommandNotAvailable();
2654 }
2655
2656 ec.clear();
2657 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002658 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302659 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2660 restricionModeProperty,
2661 static_cast<std::variant<std::string>>(
2662 securityNameSpace::convertForMessage(reqMode)));
2663
2664 if (ec)
2665 {
2666 phosphor::logging::log<phosphor::logging::level::ERR>(
2667 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2668 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2669 return ipmi::responseUnspecifiedError();
2670 }
2671 return ipmi::responseSuccess();
2672}
2673
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002674ipmi::RspType<uint8_t /* restore status */>
2675 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2676{
2677 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2678
2679 if (clr != expClr)
2680 {
2681 return ipmi::responseInvalidFieldRequest();
2682 }
2683 constexpr uint8_t cmdStatus = 0;
2684 constexpr uint8_t cmdDefaultRestore = 0xaa;
2685 constexpr uint8_t cmdFullRestore = 0xbb;
2686 constexpr uint8_t cmdFormat = 0xcc;
2687
2688 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2689
2690 switch (cmd)
2691 {
2692 case cmdStatus:
2693 break;
2694 case cmdDefaultRestore:
2695 case cmdFullRestore:
2696 case cmdFormat:
2697 {
2698 // write file to rwfs root
2699 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2700 std::ofstream restoreFile(restoreOpFname);
2701 if (!restoreFile)
2702 {
2703 return ipmi::responseUnspecifiedError();
2704 }
2705 restoreFile << value << "\n";
2706 break;
2707 }
2708 default:
2709 return ipmi::responseInvalidFieldRequest();
2710 }
2711
2712 constexpr uint8_t restorePending = 0;
2713 constexpr uint8_t restoreComplete = 1;
2714
2715 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2716 ? restorePending
2717 : restoreComplete;
2718 return ipmi::responseSuccess(restoreStatus);
2719}
2720
Chen Yugang39736d52019-07-12 16:24:33 +08002721ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2722{
2723 uint8_t bmcSource;
2724 namespace nmi = sdbusplus::com::intel::Control::server;
2725
2726 try
2727 {
2728 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2729 std::string service =
2730 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2731 Value variant =
2732 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2733 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2734
2735 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2736 std::get<std::string>(variant)))
2737 {
2738 case nmi::NMISource::BMCSourceSignal::None:
2739 bmcSource = static_cast<uint8_t>(NmiSource::none);
2740 break;
2741 case nmi::NMISource::BMCSourceSignal::FpBtn:
2742 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
2743 break;
2744 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
2745 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
2746 break;
2747 case nmi::NMISource::BMCSourceSignal::PefMatch:
2748 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
2749 break;
2750 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2751 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2752 break;
2753 case nmi::NMISource::BMCSourceSignal::MemoryError:
2754 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2755 break;
2756 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
2757 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
2758 break;
2759 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
2760 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
2761 break;
2762 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
2763 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
2764 break;
2765 default:
2766 phosphor::logging::log<phosphor::logging::level::ERR>(
2767 "NMI source: invalid property!",
2768 phosphor::logging::entry(
2769 "PROP=%s", std::get<std::string>(variant).c_str()));
2770 return ipmi::responseResponseError();
2771 }
2772 }
2773 catch (sdbusplus::exception::SdBusError& e)
2774 {
2775 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2776 return ipmi::responseResponseError();
2777 }
2778
2779 return ipmi::responseSuccess(bmcSource);
2780}
2781
2782ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2783{
2784 namespace nmi = sdbusplus::com::intel::Control::server;
2785
2786 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2787 nmi::NMISource::BMCSourceSignal::None;
2788
2789 switch (NmiSource(sourceId))
2790 {
2791 case NmiSource::none:
2792 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2793 break;
2794 case NmiSource::fpBtn:
2795 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2796 break;
2797 case NmiSource::wdPreTimeout:
2798 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2799 break;
2800 case NmiSource::pefMatch:
2801 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2802 break;
2803 case NmiSource::chassisCmd:
2804 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2805 break;
2806 case NmiSource::memoryError:
2807 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2808 break;
2809 case NmiSource::pciSerrPerr:
2810 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2811 break;
2812 case NmiSource::southbridgeNmi:
2813 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2814 break;
2815 case NmiSource::chipsetNmi:
2816 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2817 break;
2818 default:
2819 phosphor::logging::log<phosphor::logging::level::ERR>(
2820 "NMI source: invalid property!");
2821 return ipmi::responseResponseError();
2822 }
2823
2824 try
2825 {
2826 // keep NMI signal source
2827 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2828 std::string service =
2829 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2830 setDbusProperty(
2831 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2832 oemNmiBmcSourceObjPathProp,
2833 sdbusplus::com::intel::Control::server::convertForMessage(
2834 bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002835 // set Enabled property to inform NMI source handling
2836 // to trigger a NMI_OUT BSOD.
2837 // if it's triggered by NMI source property changed,
2838 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2839 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2840 {
2841 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2842 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2843 static_cast<bool>(true));
2844 }
Chen Yugang39736d52019-07-12 16:24:33 +08002845 }
2846 catch (sdbusplus::exception_t& e)
2847 {
2848 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2849 return ipmi::responseResponseError();
2850 }
2851
2852 return ipmi::responseSuccess();
2853}
2854
James Feist63efafa2019-07-24 12:39:21 -07002855namespace dimmOffset
2856{
2857constexpr const char* dimmPower = "DimmPower";
2858constexpr const char* staticCltt = "StaticCltt";
2859constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2860constexpr const char* offsetInterface =
2861 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2862constexpr const char* property = "DimmOffset";
2863
2864}; // namespace dimmOffset
2865
2866ipmi::RspType<>
2867 ipmiOEMSetDimmOffset(uint8_t type,
2868 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2869{
2870 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2871 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2872 {
2873 return ipmi::responseInvalidFieldRequest();
2874 }
2875
2876 if (data.empty())
2877 {
2878 return ipmi::responseInvalidFieldRequest();
2879 }
2880 nlohmann::json json;
2881
2882 std::ifstream jsonStream(dimmOffsetFile);
2883 if (jsonStream.good())
2884 {
2885 json = nlohmann::json::parse(jsonStream, nullptr, false);
2886 if (json.is_discarded())
2887 {
2888 json = nlohmann::json();
2889 }
2890 jsonStream.close();
2891 }
2892
2893 std::string typeName;
2894 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2895 {
2896 typeName = dimmOffset::dimmPower;
2897 }
2898 else
2899 {
2900 typeName = dimmOffset::staticCltt;
2901 }
2902
2903 nlohmann::json& field = json[typeName];
2904
2905 for (const auto& [index, value] : data)
2906 {
2907 field[index] = value;
2908 }
2909
2910 for (nlohmann::json& val : field)
2911 {
2912 if (val == nullptr)
2913 {
2914 val = static_cast<uint8_t>(0);
2915 }
2916 }
2917
2918 std::ofstream output(dimmOffsetFile);
2919 if (!output.good())
2920 {
2921 std::cerr << "Error writing json file\n";
2922 return ipmi::responseResponseError();
2923 }
2924
2925 output << json.dump(4);
2926
2927 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2928 {
2929 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
2930
2931 std::variant<std::vector<uint8_t>> offsets =
2932 field.get<std::vector<uint8_t>>();
2933 auto call = bus->new_method_call(
2934 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
2935 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
2936 try
2937 {
2938 bus->call(call);
2939 }
2940 catch (sdbusplus::exception_t& e)
2941 {
2942 phosphor::logging::log<phosphor::logging::level::ERR>(
2943 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
2944 phosphor::logging::entry("ERR=%s", e.what()));
2945 return ipmi::responseResponseError();
2946 }
2947 }
2948
2949 return ipmi::responseSuccess();
2950}
2951
2952ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
2953{
2954
2955 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2956 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2957 {
2958 return ipmi::responseInvalidFieldRequest();
2959 }
2960
2961 std::ifstream jsonStream(dimmOffsetFile);
2962
2963 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
2964 if (json.is_discarded())
2965 {
2966 std::cerr << "File error in " << dimmOffsetFile << "\n";
2967 return ipmi::responseResponseError();
2968 }
2969
2970 std::string typeName;
2971 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2972 {
2973 typeName = dimmOffset::dimmPower;
2974 }
2975 else
2976 {
2977 typeName = dimmOffset::staticCltt;
2978 }
2979
2980 auto it = json.find(typeName);
2981 if (it == json.end())
2982 {
2983 return ipmi::responseInvalidFieldRequest();
2984 }
2985
2986 if (it->size() <= index)
2987 {
2988 return ipmi::responseInvalidFieldRequest();
2989 }
2990
2991 uint8_t resp = it->at(index).get<uint8_t>();
2992 return ipmi::responseSuccess(resp);
2993}
2994
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08002995namespace boot_options
2996{
2997
2998using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
2999using IpmiValue = uint8_t;
3000constexpr auto ipmiDefault = 0;
3001
3002std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3003 {0x01, Source::Sources::Network},
3004 {0x02, Source::Sources::Disk},
3005 {0x05, Source::Sources::ExternalMedia},
3006 {0x0f, Source::Sources::RemovableMedia},
3007 {ipmiDefault, Source::Sources::Default}};
3008
3009std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003010 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003011
3012std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3013 {Source::Sources::Network, 0x01},
3014 {Source::Sources::Disk, 0x02},
3015 {Source::Sources::ExternalMedia, 0x05},
3016 {Source::Sources::RemovableMedia, 0x0f},
3017 {Source::Sources::Default, ipmiDefault}};
3018
3019std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003020 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003021
3022static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3023static constexpr auto bootSourceIntf =
3024 "xyz.openbmc_project.Control.Boot.Source";
3025static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3026static constexpr auto persistentObjPath =
3027 "/xyz/openbmc_project/control/host0/boot";
3028static constexpr auto oneTimePath =
3029 "/xyz/openbmc_project/control/host0/boot/one_time";
3030static constexpr auto bootSourceProp = "BootSource";
3031static constexpr auto bootModeProp = "BootMode";
3032static constexpr auto oneTimeBootEnableProp = "Enabled";
3033static constexpr auto httpBootMode =
3034 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3035
3036enum class BootOptionParameter : size_t
3037{
3038 setInProgress = 0x0,
3039 bootFlags = 0x5,
3040};
3041static constexpr uint8_t setComplete = 0x0;
3042static constexpr uint8_t setInProgress = 0x1;
3043static uint8_t transferStatus = setComplete;
3044static constexpr uint8_t setParmVersion = 0x01;
3045static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3046static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3047static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3048static constexpr uint8_t httpBoot = 0xd;
3049static constexpr uint8_t bootSourceMask = 0x3c;
3050
3051} // namespace boot_options
3052
3053ipmi::RspType<uint8_t, // version
3054 uint8_t, // param
3055 uint8_t, // data0, dependent on parameter
3056 std::optional<uint8_t> // data1, dependent on parameter
3057 >
3058 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3059{
3060 using namespace boot_options;
3061 uint8_t bootOption = 0;
3062
3063 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3064 {
3065 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3066 std::nullopt);
3067 }
3068
3069 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3070 {
3071 phosphor::logging::log<phosphor::logging::level::ERR>(
3072 "Unsupported parameter");
3073 return ipmi::responseResponseError();
3074 }
3075
3076 try
3077 {
3078 auto oneTimeEnabled = false;
3079 // read one time Enabled property
3080 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3081 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3082 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3083 enabledIntf, oneTimeBootEnableProp);
3084 oneTimeEnabled = std::get<bool>(variant);
3085
3086 // get BootSource and BootMode properties
3087 // according to oneTimeEnable
3088 auto bootObjPath = oneTimePath;
3089 if (oneTimeEnabled == false)
3090 {
3091 bootObjPath = persistentObjPath;
3092 }
3093
3094 service = getService(*dbus, bootModeIntf, bootObjPath);
3095 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3096 bootModeProp);
3097
3098 auto bootMode =
3099 Mode::convertModesFromString(std::get<std::string>(variant));
3100
3101 service = getService(*dbus, bootSourceIntf, bootObjPath);
3102 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3103 bootSourceProp);
3104
3105 if (std::get<std::string>(variant) == httpBootMode)
3106 {
3107 bootOption = httpBoot;
3108 }
3109 else
3110 {
3111 auto bootSource = Source::convertSourcesFromString(
3112 std::get<std::string>(variant));
3113 bootOption = sourceDbusToIpmi.at(bootSource);
3114 if (Source::Sources::Default == bootSource)
3115 {
3116 bootOption = modeDbusToIpmi.at(bootMode);
3117 }
3118 }
3119
3120 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3121 : setParmBootFlagsValidPermanent;
3122 bootOption <<= 2; // shift for responseconstexpr
3123 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3124 bootOption);
3125 }
3126 catch (sdbusplus::exception_t& e)
3127 {
3128 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3129 return ipmi::responseResponseError();
3130 }
3131}
3132
3133ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3134 std::optional<uint8_t> bootOption)
3135{
3136 using namespace boot_options;
3137 auto oneTimeEnabled = false;
3138
3139 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3140 {
3141 if (bootOption)
3142 {
3143 return ipmi::responseReqDataLenInvalid();
3144 }
3145
3146 if (transferStatus == setInProgress)
3147 {
3148 phosphor::logging::log<phosphor::logging::level::ERR>(
3149 "boot option set in progress!");
3150 return ipmi::responseResponseError();
3151 }
3152
3153 transferStatus = bootParam;
3154 return ipmi::responseSuccess();
3155 }
3156
3157 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3158 {
3159 phosphor::logging::log<phosphor::logging::level::ERR>(
3160 "Unsupported parameter");
3161 return ipmi::responseResponseError();
3162 }
3163
3164 if (!bootOption)
3165 {
3166 return ipmi::responseReqDataLenInvalid();
3167 }
3168
3169 if (((bootOption.value() & bootSourceMask) >> 2) !=
3170 httpBoot) // not http boot, exit
3171 {
3172 phosphor::logging::log<phosphor::logging::level::ERR>(
3173 "wrong boot option parameter!");
3174 return ipmi::responseParmOutOfRange();
3175 }
3176
3177 try
3178 {
3179 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3180 setParmBootFlagsPermanent;
3181
3182 // read one time Enabled property
3183 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3184 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3185 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3186 enabledIntf, oneTimeBootEnableProp);
3187 oneTimeEnabled = std::get<bool>(variant);
3188
3189 /*
3190 * Check if the current boot setting is onetime or permanent, if the
3191 * request in the command is otherwise, then set the "Enabled"
3192 * property in one_time object path to 'True' to indicate onetime
3193 * and 'False' to indicate permanent.
3194 *
3195 * Once the onetime/permanent setting is applied, then the bootMode
3196 * and bootSource is updated for the corresponding object.
3197 */
3198 if (permanent == oneTimeEnabled)
3199 {
3200 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3201 oneTimeBootEnableProp, !permanent);
3202 }
3203
3204 // set BootSource and BootMode properties
3205 // according to oneTimeEnable or persistent
3206 auto bootObjPath = oneTimePath;
3207 if (oneTimeEnabled == false)
3208 {
3209 bootObjPath = persistentObjPath;
3210 }
3211 std::string bootMode =
3212 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3213 std::string bootSource = httpBootMode;
3214
3215 service = getService(*dbus, bootModeIntf, bootObjPath);
3216 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3217 bootMode);
3218
3219 service = getService(*dbus, bootSourceIntf, bootObjPath);
3220 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3221 bootSourceProp, bootSource);
3222 }
3223 catch (sdbusplus::exception_t& e)
3224 {
3225 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3226 return ipmi::responseResponseError();
3227 }
3228
3229 return ipmi::responseSuccess();
3230}
3231
Chen Yugangdd6122b2019-09-24 07:44:50 +08003232ipmi::RspType<>
3233 ipmiOemSetBootOptions(uint8_t bootFlag, uint8_t bootParam,
3234 std::optional<uint8_t> bootOption,
3235 std::optional<std::array<uint8_t, 3>> bootResv)
Chen Yugangca12a7b2019-09-03 18:11:44 +08003236{
3237 bool oneTimeEnabled = false;
3238 uint8_t bootOptionValue = 0;
3239 static constexpr const uint8_t shiftBits = 2;
3240
3241 if (bootFlag ==
3242 static_cast<uint8_t>(boot_options::BootOptionParameter::setInProgress))
3243 {
3244 if (bootOption)
3245 {
3246 return ipmi::responseReqDataLenInvalid();
3247 }
3248
Chen Yugangca12a7b2019-09-03 18:11:44 +08003249 boot_options::transferStatus = bootParam;
3250 return ipmi::responseSuccess();
3251 }
3252
3253 if (bootFlag !=
3254 static_cast<uint8_t>(boot_options::BootOptionParameter::bootFlags))
3255 {
3256 phosphor::logging::log<phosphor::logging::level::ERR>(
3257 "Unsupported parameter");
3258 return ipmi::responseResponseError();
3259 }
3260
3261 if (!bootOption)
3262 {
3263 return ipmi::responseReqDataLenInvalid();
3264 }
3265 bootOptionValue =
3266 (bootOption.value() & boot_options::bootSourceMask) >> shiftBits;
3267
3268 try
3269 {
3270 bool permanent =
3271 (bootParam & boot_options::setParmBootFlagsPermanent) ==
3272 boot_options::setParmBootFlagsPermanent;
3273 auto bootMode = boot_options::Mode::Modes::Regular;
3274 auto bootSource = boot_options::Source::Sources::Default;
3275
3276 // read one time Enabled property
3277 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3278 std::string service = getService(*dbus, boot_options::enabledIntf,
3279 boot_options::oneTimePath);
3280 Value variant = getDbusProperty(
3281 *dbus, service, boot_options::oneTimePath,
3282 boot_options::enabledIntf, boot_options::oneTimeBootEnableProp);
Chen Yugang93113b72019-10-09 08:42:28 +08003283 auto pTmp = std::get_if<bool>(&variant);
3284 if (pTmp != nullptr)
3285 {
3286 oneTimeEnabled = *pTmp;
3287 }
Chen Yugangca12a7b2019-09-03 18:11:44 +08003288
3289 /*
3290 * Check if the current boot setting is onetime or permanent, if the
3291 * request in the command is otherwise, then set the "Enabled"
3292 * property in one_time object path to 'True' to indicate onetime
3293 * and 'False' to indicate permanent.
3294 *
3295 * Once the onetime/permanent setting is applied, then the bootMode
3296 * and bootSource is updated for the corresponding object.
3297 */
3298 if (permanent == oneTimeEnabled)
3299 {
3300 setDbusProperty(*dbus, service, boot_options::oneTimePath,
3301 boot_options::enabledIntf,
3302 boot_options::oneTimeBootEnableProp, !permanent);
Chen Yugang93113b72019-10-09 08:42:28 +08003303 oneTimeEnabled = !permanent;
Chen Yugangca12a7b2019-09-03 18:11:44 +08003304 }
3305
3306 // set BootSource and BootMode properties
3307 // according to oneTimeEnable or persistent
3308 auto bootObjPath = boot_options::oneTimePath;
3309 if (oneTimeEnabled == false)
3310 {
3311 bootObjPath = boot_options::persistentObjPath;
3312 }
3313
3314 auto modeItr = boot_options::modeIpmiToDbus.find(bootOptionValue);
3315 auto sourceItr = boot_options::sourceIpmiToDbus.find(bootOptionValue);
3316
3317 if (boot_options::sourceIpmiToDbus.end() != sourceItr)
3318 {
3319 bootSource = sourceItr->second;
3320 }
3321
3322 if (boot_options::modeIpmiToDbus.end() != modeItr)
3323 {
3324 bootMode = modeItr->second;
3325 }
3326
3327 if ((boot_options::modeIpmiToDbus.end() == modeItr) &&
3328 (boot_options::sourceIpmiToDbus.end() == sourceItr))
3329 {
3330 // return error if boot option is not supported
3331 return ipmi::responseInvalidFieldRequest();
3332 }
3333 service = getService(*dbus, boot_options::bootModeIntf, bootObjPath);
3334 setDbusProperty(*dbus, service, bootObjPath, boot_options::bootModeIntf,
3335 boot_options::bootModeProp,
3336 convertForMessage(bootMode));
3337
3338 service = getService(*dbus, boot_options::bootSourceIntf, bootObjPath);
3339 setDbusProperty(
3340 *dbus, service, bootObjPath, boot_options::bootSourceIntf,
3341 boot_options::bootSourceProp, convertForMessage(bootSource));
3342 }
3343 catch (sdbusplus::exception_t& e)
3344 {
3345 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3346 return ipmi::responseResponseError();
3347 }
3348
3349 return ipmi::responseSuccess();
3350}
3351
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003352using BasicVariantType =
3353 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3354 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3355 uint16_t, uint8_t, bool>;
3356using PropertyMapType =
3357 boost::container::flat_map<std::string, BasicVariantType>;
3358static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3359 "xyz.openbmc_project.Configuration.PSUPresence"};
3360int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3361 std::vector<uint64_t>& addrTable)
3362{
3363 boost::system::error_code ec;
3364 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3365 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3366 "/xyz/openbmc_project/object_mapper",
3367 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3368 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3369 if (ec)
3370 {
3371 phosphor::logging::log<phosphor::logging::level::ERR>(
3372 "Failed to set dbus property to cold redundancy");
3373 return -1;
3374 }
3375 for (const auto& object : subtree)
3376 {
3377 std::string pathName = object.first;
3378 for (const auto& serviceIface : object.second)
3379 {
3380 std::string serviceName = serviceIface.first;
3381
3382 ec.clear();
3383 PropertyMapType propMap =
3384 ctx->bus->yield_method_call<PropertyMapType>(
3385 ctx->yield, ec, serviceName, pathName,
3386 "org.freedesktop.DBus.Properties", "GetAll",
3387 "xyz.openbmc_project.Configuration.PSUPresence");
3388 if (ec)
3389 {
3390 phosphor::logging::log<phosphor::logging::level::ERR>(
3391 "Failed to set dbus property to cold redundancy");
3392 return -1;
3393 }
3394 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3395 auto psuAddress =
3396 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3397
3398 if (psuBus == nullptr || psuAddress == nullptr)
3399 {
3400 std::cerr << "error finding necessary "
3401 "entry in configuration\n";
3402 return -1;
3403 }
3404 bus = static_cast<uint8_t>(*psuBus);
3405 addrTable = *psuAddress;
3406 return 0;
3407 }
3408 }
3409 return -1;
3410}
3411
3412static const constexpr uint8_t addrOffset = 8;
3413static const constexpr uint8_t psuRevision = 0xd9;
3414static const constexpr uint8_t defaultPSUBus = 7;
3415// Second Minor, Primary Minor, Major
3416static const constexpr size_t verLen = 3;
3417ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3418{
3419 uint8_t bus = defaultPSUBus;
3420 std::vector<uint64_t> addrTable;
3421 std::vector<uint8_t> result;
3422 if (getPSUAddress(ctx, bus, addrTable))
3423 {
3424 std::cerr << "Failed to get PSU bus and address\n";
3425 return ipmi::responseResponseError();
3426 }
3427
3428 for (const auto& slaveAddr : addrTable)
3429 {
3430 std::vector<uint8_t> writeData = {psuRevision};
3431 std::vector<uint8_t> readBuf(verLen);
3432 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3433 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3434
3435 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3436 if (retI2C != ipmi::ccSuccess)
3437 {
3438 for (size_t idx = 0; idx < verLen; idx++)
3439 {
3440 result.emplace_back(0x00);
3441 }
3442 }
3443 else
3444 {
3445 for (const uint8_t& data : readBuf)
3446 {
3447 result.emplace_back(data);
3448 }
3449 }
3450 }
3451
3452 return ipmi::responseSuccess(result);
3453}
3454
Jason M. Bills64796042018-10-03 16:51:55 -07003455static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003456{
3457 phosphor::logging::log<phosphor::logging::level::INFO>(
3458 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003459 ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003460 ipmiOEMWildcard,
3461 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003462
3463 ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003464 ipmiOEMWildcard,
3465 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003466
3467 ipmiPrintAndRegister(intel::netFnGeneral,
3468 intel::general::cmdGetChassisIdentifier, NULL,
3469 ipmiOEMGetChassisIdentifier,
3470 PRIVILEGE_USER); // get chassis identifier
3471
3472 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3473 NULL, ipmiOEMSetSystemGUID,
3474 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003475
3476 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003477 registerHandler(prioOemBase, intel::netFnGeneral,
3478 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3479 ipmiOEMDisableBMCSystemReset);
3480
Jason M. Billsb02bf092019-08-15 13:01:56 -07003481 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003482 registerHandler(prioOemBase, intel::netFnGeneral,
3483 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3484 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003485
Vernon Mauery98bbf692019-09-16 11:14:59 -07003486 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3487 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003488
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003489 registerHandler(prioOemBase, intel::netFnGeneral,
3490 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3491 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003492
Vernon Mauery98bbf692019-09-16 11:14:59 -07003493 ipmiPrintAndRegister(intel::netFnGeneral,
3494 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3495 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303496
Vernon Mauery98bbf692019-09-16 11:14:59 -07003497 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3498 intel::general::cmdSendEmbeddedFWUpdStatus,
3499 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303500
Vernon Mauery98bbf692019-09-16 11:14:59 -07003501 ipmiPrintAndRegister(intel::netFnGeneral,
3502 intel::general::cmdSetPowerRestoreDelay, NULL,
3503 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3504
3505 ipmiPrintAndRegister(intel::netFnGeneral,
3506 intel::general::cmdGetPowerRestoreDelay, NULL,
3507 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3508
3509 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3510 intel::general::cmdSetOEMUser2Activation,
3511 Privilege::Callback, ipmiOEMSetUser2Activation);
3512
3513 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3514 intel::general::cmdSetSpecialUserPassword,
3515 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303516
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003517 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003518 registerHandler(prioOemBase, intel::netFnGeneral,
3519 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3520 ipmiOEMGetProcessorErrConfig);
3521
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003522 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003523 registerHandler(prioOemBase, intel::netFnGeneral,
3524 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3525 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003526
Vernon Mauery98bbf692019-09-16 11:14:59 -07003527 ipmiPrintAndRegister(intel::netFnGeneral,
3528 intel::general::cmdSetShutdownPolicy, NULL,
3529 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003530
Vernon Mauery98bbf692019-09-16 11:14:59 -07003531 ipmiPrintAndRegister(intel::netFnGeneral,
3532 intel::general::cmdGetShutdownPolicy, NULL,
3533 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003534
Vernon Mauery98bbf692019-09-16 11:14:59 -07003535 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetFanConfig,
3536 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
James Feist91244a62019-02-19 15:04:54 -08003537
Vernon Mauery98bbf692019-09-16 11:14:59 -07003538 registerHandler(prioOemBase, intel::netFnGeneral,
3539 intel::general::cmdGetFanConfig, Privilege::User,
3540 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003541
Vernon Mauery98bbf692019-09-16 11:14:59 -07003542 registerHandler(prioOemBase, intel::netFnGeneral,
3543 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3544 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003545
Vernon Mauery98bbf692019-09-16 11:14:59 -07003546 registerHandler(prioOemBase, intel::netFnGeneral,
3547 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3548 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003549
Vernon Mauery98bbf692019-09-16 11:14:59 -07003550 registerHandler(prioOemBase, intel::netFnGeneral,
3551 intel::general::cmdSetFscParameter, Privilege::User,
3552 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003553
Vernon Mauery98bbf692019-09-16 11:14:59 -07003554 registerHandler(prioOemBase, intel::netFnGeneral,
3555 intel::general::cmdGetFscParameter, Privilege::User,
3556 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303557
Vernon Mauery98bbf692019-09-16 11:14:59 -07003558 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3559 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3560 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003561
Vernon Mauery98bbf692019-09-16 11:14:59 -07003562 registerHandler(prioOemBase, intel::netFnGeneral,
3563 intel::general::cmdGetNmiStatus, Privilege::User,
3564 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003565
Vernon Mauery98bbf692019-09-16 11:14:59 -07003566 registerHandler(prioOemBase, intel::netFnGeneral,
3567 intel::general::cmdSetNmiStatus, Privilege::Operator,
3568 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003569
Vernon Mauery98bbf692019-09-16 11:14:59 -07003570 registerHandler(prioOemBase, intel::netFnGeneral,
3571 intel::general::cmdGetEfiBootOptions, Privilege::User,
3572 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003573
Vernon Mauery98bbf692019-09-16 11:14:59 -07003574 registerHandler(prioOemBase, intel::netFnGeneral,
3575 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3576 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303577
Vernon Mauery98bbf692019-09-16 11:14:59 -07003578 registerHandler(prioOemBase, intel::netFnGeneral,
3579 intel::general::cmdGetSecurityMode, Privilege::User,
3580 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303581
Vernon Mauery98bbf692019-09-16 11:14:59 -07003582 registerHandler(prioOemBase, intel::netFnGeneral,
3583 intel::general::cmdSetSecurityMode, Privilege::Admin,
3584 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003585
Vernon Mauery98bbf692019-09-16 11:14:59 -07003586 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3587 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003588
Vernon Mauery98bbf692019-09-16 11:14:59 -07003589 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3590 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3591 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3592
3593 registerHandler(prioOemBase, intel::netFnGeneral,
3594 intel::general::cmdSetFaultIndication, Privilege::Operator,
3595 ipmiOEMSetFaultIndication);
3596
3597 registerHandler(prioOemBase, intel::netFnGeneral,
3598 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3599 ipmiOEMSetCRConfig);
3600
3601 registerHandler(prioOemBase, intel::netFnGeneral,
3602 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3603 ipmiOEMGetCRConfig);
3604
3605 registerHandler(prioOemBase, intel::netFnGeneral,
3606 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003607 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003608
Vernon Mauery98bbf692019-09-16 11:14:59 -07003609 registerHandler(prioOemBase, intel::netFnGeneral,
3610 intel::general::cmdSetDimmOffset, Privilege::Operator,
3611 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003612
Vernon Mauery98bbf692019-09-16 11:14:59 -07003613 registerHandler(prioOemBase, intel::netFnGeneral,
3614 intel::general::cmdGetDimmOffset, Privilege::Operator,
3615 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003616
Vernon Mauery98bbf692019-09-16 11:14:59 -07003617 registerHandler(prioOemBase, netFnChassis, chassis::cmdSetSystemBootOptions,
3618 Privilege::Operator, ipmiOemSetBootOptions);
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003619
3620 registerHandler(prioOemBase, intel::netFnGeneral,
3621 intel::general::cmdGetPSUVersion, Privilege::User,
3622 ipmiOEMGetPSUVersion);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003623}
3624
3625} // namespace ipmi