blob: 521c454385e332941662c94b899a915dd0eddf0c [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>
Yong Li0669d192019-05-06 14:01:46 +080027#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070028#include <commandutils.hpp>
Vernon Mauery4ac799d2019-05-20 15:50:37 -070029#include <filesystem>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080030#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080031#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070032#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070033#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <phosphor-logging/log.hpp>
Chen Yugang7a04f3a2019-10-08 11:12:35 +080036#include <regex>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080037#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053038#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080039#include <string>
James Feist91244a62019-02-19 15:04:54 -080040#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080041#include <vector>
Chen Yugang97cf96e2019-11-01 08:55:11 +080042#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
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>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053047#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080048
49namespace ipmi
50{
Jason M. Bills64796042018-10-03 16:51:55 -070051static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070052
Jason M. Bills64796042018-10-03 16:51:55 -070053static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080054
Suryakanth Sekard509eb92018-11-15 17:44:11 +053055static constexpr auto ethernetIntf =
56 "xyz.openbmc_project.Network.EthernetInterface";
57static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
58static constexpr auto networkService = "xyz.openbmc_project.Network";
59static constexpr auto networkRoot = "/xyz/openbmc_project/network";
60
Chen Yugang97cf96e2019-11-01 08:55:11 +080061static constexpr const char* oemNmiSourceIntf =
62 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080063static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080064 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080065static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
66static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
67
James Feist63efafa2019-07-24 12:39:21 -070068static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
69
Chen Yugang39736d52019-07-12 16:24:33 +080070enum class NmiSource : uint8_t
71{
72 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080073 frontPanelButton = 1,
74 watchdog = 2,
75 chassisCmd = 3,
76 memoryError = 4,
77 pciBusError = 5,
78 pch = 6,
79 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080080};
81
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053082static constexpr const char* restricionModeService =
83 "xyz.openbmc_project.RestrictionMode.Manager";
84static constexpr const char* restricionModeBasePath =
85 "/xyz/openbmc_project/control/security/restriction_mode";
86static constexpr const char* restricionModeIntf =
87 "xyz.openbmc_project.Control.Security.RestrictionMode";
88static constexpr const char* restricionModeProperty = "RestrictionMode";
89
90static constexpr const char* specialModeService =
91 "xyz.openbmc_project.SpecialMode";
92static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +053093 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053094static constexpr const char* specialModeIntf =
95 "xyz.openbmc_project.Security.SpecialMode";
96static constexpr const char* specialModeProperty = "SpecialMode";
97
98static constexpr const char* dBusPropertyIntf =
99 "org.freedesktop.DBus.Properties";
100static constexpr const char* dBusPropertyGetMethod = "Get";
101static constexpr const char* dBusPropertySetMethod = "Set";
102
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800103// return code: 0 successful
104int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
105{
106 std::string objpath = "/xyz/openbmc_project/FruDevice";
107 std::string intf = "xyz.openbmc_project.FruDeviceManager";
108 std::string service = getService(bus, intf, objpath);
109 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
110 if (valueTree.empty())
111 {
112 phosphor::logging::log<phosphor::logging::level::ERR>(
113 "No object implements interface",
114 phosphor::logging::entry("INTF=%s", intf.c_str()));
115 return -1;
116 }
117
Jason M. Bills64796042018-10-03 16:51:55 -0700118 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800119 {
120 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
121 if (interface == item.second.end())
122 {
123 continue;
124 }
125
126 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
127 if (property == interface->second.end())
128 {
129 continue;
130 }
131
132 try
133 {
134 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700135 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700136 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800137 {
138 phosphor::logging::log<phosphor::logging::level::ERR>(
139 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800140 return -1;
141 }
Jason M. Bills64796042018-10-03 16:51:55 -0700142 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800143 return 0;
144 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700145 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800146 {
Jason M. Bills64796042018-10-03 16:51:55 -0700147 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800148 return -1;
149 }
150 }
151 return -1;
152}
Jason M. Bills64796042018-10-03 16:51:55 -0700153
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
155 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700156 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800157{
Jason M. Bills64796042018-10-03 16:51:55 -0700158 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800159 // Status code.
160 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700161 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162 return rc;
163}
164
165// Returns the Chassis Identifier (serial #)
166ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
167 ipmi_request_t request,
168 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700169 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800170 ipmi_context_t context)
171{
172 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700173 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800174 {
Jason M. Bills64796042018-10-03 16:51:55 -0700175 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800176 return IPMI_CC_REQ_DATA_LEN_INVALID;
177 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700178 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
179 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800180 {
Jason M. Bills64796042018-10-03 16:51:55 -0700181 *dataLen = serial.size(); // length will never exceed response length
182 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700184 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800185 return IPMI_CC_OK;
186 }
Jason M. Bills64796042018-10-03 16:51:55 -0700187 *dataLen = 0;
188 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800189}
190
191ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
192 ipmi_request_t request,
193 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700194 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800195{
196 static constexpr size_t safeBufferLength = 50;
197 char buf[safeBufferLength] = {0};
198 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
199
Jason M. Bills64796042018-10-03 16:51:55 -0700200 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800201 {
Jason M. Bills64796042018-10-03 16:51:55 -0700202 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800203 return IPMI_CC_REQ_DATA_LEN_INVALID;
204 }
205
Jason M. Bills64796042018-10-03 16:51:55 -0700206 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800207
208 snprintf(
209 buf, safeBufferLength,
210 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
211 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
212 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
213 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
214 Data->node3, Data->node2, Data->node1);
215 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
216 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800217
218 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
219 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700220 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
221 std::string service = getService(*dbus, intf, objpath);
222 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800223 return IPMI_CC_OK;
224}
225
Jason M. Billsb02bf092019-08-15 13:01:56 -0700226ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
227 uint7_t reserved1)
228{
229 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
230
231 try
232 {
233 auto service =
234 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
235 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
236 bmcResetDisablesIntf, "ResetOnSMI",
237 !disableResetOnSMI);
238 }
239 catch (std::exception& e)
240 {
241 phosphor::logging::log<phosphor::logging::level::ERR>(
242 "Failed to set BMC reset disables",
243 phosphor::logging::entry("EXCEPTION=%s", e.what()));
244 return ipmi::responseUnspecifiedError();
245 }
246
247 return ipmi::responseSuccess();
248}
249
250ipmi::RspType<bool, // disableResetOnSMI
251 uint7_t // reserved
252 >
253 ipmiOEMGetBMCResetDisables()
254{
255 bool disableResetOnSMI = true;
256
257 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
258 try
259 {
260 auto service =
261 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
262 Value variant =
263 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
264 bmcResetDisablesIntf, "ResetOnSMI");
265 disableResetOnSMI = !std::get<bool>(variant);
266 }
267 catch (std::exception& e)
268 {
269 phosphor::logging::log<phosphor::logging::level::ERR>(
270 "Failed to get BMC reset disables",
271 phosphor::logging::entry("EXCEPTION=%s", e.what()));
272 return ipmi::responseUnspecifiedError();
273 }
274
275 return ipmi::responseSuccess(disableResetOnSMI, 0);
276}
277
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800278ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
279 ipmi_request_t request, ipmi_response_t response,
280 ipmi_data_len_t dataLen, ipmi_context_t context)
281{
282 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
283
Jason M. Bills64796042018-10-03 16:51:55 -0700284 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800285 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800286 *dataLen = 0;
287 return IPMI_CC_REQ_DATA_LEN_INVALID;
288 }
Jason M. Bills64796042018-10-03 16:51:55 -0700289 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800290
Vernon Mauery15419dd2019-05-24 09:40:30 -0700291 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
292 std::string service = getService(*dbus, biosIntf, biosObjPath);
293 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800294 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
295 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700296 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297 *dataLen = 1;
298 return IPMI_CC_OK;
299}
300
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800301bool getSwVerInfo(uint8_t& bmcMajor, uint8_t& bmcMinor, uint8_t& meMajor,
302 uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800303{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800304 // step 1 : get BMC Major and Minor numbers from its DBUS property
305 std::optional<MetaRevision> rev{};
306 try
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800308 std::string version = getActiveSoftwareVersionInfo();
309 rev = convertIntelVersion(version);
310 }
311 catch (const std::exception& e)
312 {
313 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800314 }
315
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800316 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800317 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800318 MetaRevision revision = rev.value();
319 bmcMajor = revision.major;
320
321 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
322 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
323 }
324
325 // step 2 : get ME Major and Minor numbers from its DBUS property
326 try
327 {
328 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
329 std::string service =
330 getService(*dbus, "xyz.openbmc_project.Software.Version",
331 "/xyz/openbmc_project/me_version");
332 Value variant =
333 getDbusProperty(*dbus, service, "/xyz/openbmc_project/me_version",
334 "xyz.openbmc_project.Software.Version", "Version");
335
336 std::string& meString = std::get<std::string>(variant);
337
338 // get ME major number
339 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
340 constexpr size_t matchedPhosphor = 6;
341 std::smatch results;
342 if (std::regex_match(meString, results, pattern1))
343 {
344 if (results.size() == matchedPhosphor)
345 {
346 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
347 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
348 }
349 }
350 }
351 catch (sdbusplus::exception::SdBusError& e)
352 {
353 return false;
354 }
355 return true;
356}
357
358ipmi::RspType<
359 std::variant<std::string,
360 std::tuple<uint8_t, std::array<uint8_t, 2>,
361 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
362 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
363 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
364 ipmiOEMGetDeviceInfo(uint8_t entityType, uint8_t countToRead,
365 uint8_t offset)
366{
367 if (countToRead == 0)
368 {
369 return ipmi::responseReqDataLenInvalid();
370 }
371
372 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
373 {
374 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800375 }
376
377 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800378 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800379 {
380 case OEMDevEntityType::biosId:
381 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700382 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
383 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800384 try
385 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700386 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800387 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700388 std::string& idString = std::get<std::string>(variant);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800389 if (offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800390 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800391 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800392 }
Jason M. Bills64796042018-10-03 16:51:55 -0700393 size_t length = 0;
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800394 if (countToRead > (idString.size() - offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700395 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800396 length = idString.size() - offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700397 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800398 else
399 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800400 length = countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800401 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800402
403 std::string readBuf = {0};
404 readBuf.resize(length);
405 std::copy_n(idString.begin() + offset, length,
406 (readBuf.begin()));
407 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800408 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700409 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800410 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800411 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800412 }
413 }
414 break;
415
416 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800417 {
418 constexpr const size_t verLen = 2;
419 constexpr const size_t verTotalLen = 10;
420 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
421 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
422 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
423 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
424 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
425 // data0/1: BMC version number; data6/7: ME version number
426 // the others: HSC0/1/2 version number, not avaible.
427 if (true != getSwVerInfo(bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
428 {
429 return ipmi::responseUnspecifiedError();
430 }
431 return ipmi::responseSuccess(
432 std::tuple<
433 uint8_t, std::array<uint8_t, verLen>,
434 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
435 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
436 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
437 }
438 break;
439
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800440 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800441 {
442 constexpr const size_t sdrLen = 2;
443 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
444 return ipmi::responseSuccess(
445 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
446 readBuf});
447 }
448 break;
449
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800450 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800451 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800452 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800453}
454
455ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
456 ipmi_request_t request, ipmi_response_t response,
457 ipmi_data_len_t dataLen, ipmi_context_t context)
458{
459 if (*dataLen != 0)
460 {
Jason M. Bills64796042018-10-03 16:51:55 -0700461 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800462 return IPMI_CC_REQ_DATA_LEN_INVALID;
463 }
464
465 *dataLen = 1;
466 uint8_t* res = reinterpret_cast<uint8_t*>(response);
467 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
468 // AIC is available so that BIOS will not timeout repeatly which leads to
469 // slow booting.
470 *res = 0; // Byte1=Count of SlotPosition/FruID records.
471 return IPMI_CC_OK;
472}
473
Jason M. Bills64796042018-10-03 16:51:55 -0700474ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
475 ipmi_request_t request,
476 ipmi_response_t response,
477 ipmi_data_len_t dataLen,
478 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800479{
Jason M. Bills64796042018-10-03 16:51:55 -0700480 GetPowerRestoreDelayRes* resp =
481 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
482
483 if (*dataLen != 0)
484 {
485 *dataLen = 0;
486 return IPMI_CC_REQ_DATA_LEN_INVALID;
487 }
488
Vernon Mauery15419dd2019-05-24 09:40:30 -0700489 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700490 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700491 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700492 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700493 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700494 powerRestoreDelayIntf, powerRestoreDelayProp);
495
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700496 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700497 resp->byteLSB = delay;
498 resp->byteMSB = delay >> 8;
499
500 *dataLen = sizeof(GetPowerRestoreDelayRes);
501
502 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800503}
504
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800505static uint8_t bcdToDec(uint8_t val)
506{
507 return ((val / 16 * 10) + (val % 16));
508}
509
510// Allows an update utility or system BIOS to send the status of an embedded
511// firmware update attempt to the BMC. After received, BMC will create a logging
512// record.
513ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
514 uint8_t majorRevision,
515 uint8_t minorRevision,
516 uint32_t auxInfo)
517{
518 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700519 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800520 target = (target & selEvtTargetMask) >> selEvtTargetShift;
521
522 /* make sure the status is 0, 1, or 2 as per the spec */
523 if (status > 2)
524 {
525 return ipmi::response(ipmi::ccInvalidFieldRequest);
526 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700527 /* make sure the target is 0, 1, 2, or 4 as per the spec */
528 if (target > 4 || target == 3)
529 {
530 return ipmi::response(ipmi::ccInvalidFieldRequest);
531 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800532 /*orignal OEM command is to record OEM SEL.
533 But openbmc does not support OEM SEL, so we redirect it to redfish event
534 logging. */
535 std::string buildInfo;
536 std::string action;
537 switch (FWUpdateTarget(target))
538 {
539 case FWUpdateTarget::targetBMC:
540 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700541 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800542 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
543 " BuildID: " + std::to_string(auxInfo);
544 buildInfo += std::to_string(auxInfo);
545 break;
546 case FWUpdateTarget::targetBIOS:
547 firmware = "BIOS";
548 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700549 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800550 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
551 " minor: " +
552 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
553 " ReleaseNumber: " + // ASCII encoded
554 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
555 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
556 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
557 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
558 break;
559 case FWUpdateTarget::targetME:
560 firmware = "ME";
561 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700562 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800563 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
564 " minor2: " +
565 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
566 " build1: " +
567 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
568 " build2: " +
569 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
570 break;
571 case FWUpdateTarget::targetOEMEWS:
572 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700573 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800574 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
575 " BuildID: " + std::to_string(auxInfo);
576 break;
577 }
578
Jason M. Billsdc249272019-04-03 09:58:40 -0700579 static const std::string openBMCMessageRegistryVersion("0.1");
580 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
581
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800582 switch (status)
583 {
584 case 0x0:
585 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700586 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800587 break;
588 case 0x1:
589 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700590 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800591 break;
592 case 0x2:
593 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700594 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800595 break;
596 default:
597 action = "unknown";
598 break;
599 }
600
Jason M. Billsdc249272019-04-03 09:58:40 -0700601 std::string firmwareInstanceStr =
602 firmware + " instance: " + std::to_string(instance);
603 std::string message("[firmware update] " + firmwareInstanceStr +
604 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800605
606 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700607 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
608 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
609 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800610 return ipmi::responseSuccess();
611}
612
Jason M. Bills64796042018-10-03 16:51:55 -0700613ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
614 ipmi_request_t request,
615 ipmi_response_t response,
616 ipmi_data_len_t dataLen,
617 ipmi_context_t context)
618{
619 SetPowerRestoreDelayReq* data =
620 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
621 uint16_t delay = 0;
622
623 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
624 {
625 *dataLen = 0;
626 return IPMI_CC_REQ_DATA_LEN_INVALID;
627 }
628 delay = data->byteMSB;
629 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700630 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700631 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700632 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
633 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700634 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
635 *dataLen = 0;
636
637 return IPMI_CC_OK;
638}
639
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700640static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700641{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700642 static constexpr const char* cpuPresencePathPrefix =
643 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
644 static constexpr const char* cpuPresenceIntf =
645 "xyz.openbmc_project.Inventory.Item";
646 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
647 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
648 try
Jason M. Bills64796042018-10-03 16:51:55 -0700649 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700650 auto service =
651 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
652
653 ipmi::Value result = ipmi::getDbusProperty(
654 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
655 return std::get<bool>(result);
656 }
657 catch (const std::exception& e)
658 {
659 phosphor::logging::log<phosphor::logging::level::INFO>(
660 "Cannot find processor presence",
661 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
662 return false;
663 }
664}
665
666ipmi::RspType<bool, // CATERR Reset Enabled
667 bool, // ERR2 Reset Enabled
668 uint6_t, // reserved
669 uint8_t, // reserved, returns 0x3F
670 uint6_t, // CPU1 CATERR Count
671 uint2_t, // CPU1 Status
672 uint6_t, // CPU2 CATERR Count
673 uint2_t, // CPU2 Status
674 uint6_t, // CPU3 CATERR Count
675 uint2_t, // CPU3 Status
676 uint6_t, // CPU4 CATERR Count
677 uint2_t, // CPU4 Status
678 uint8_t // Crashdump Count
679 >
680 ipmiOEMGetProcessorErrConfig()
681{
682 bool resetOnCATERR = false;
683 bool resetOnERR2 = false;
684 uint6_t cpu1CATERRCount = 0;
685 uint6_t cpu2CATERRCount = 0;
686 uint6_t cpu3CATERRCount = 0;
687 uint6_t cpu4CATERRCount = 0;
688 uint8_t crashdumpCount = 0;
689 uint2_t cpu1Status =
690 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
691 uint2_t cpu2Status =
692 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
693 uint2_t cpu3Status =
694 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
695 uint2_t cpu4Status =
696 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
697
698 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
699 try
700 {
701 auto service = ipmi::getService(*busp, processorErrConfigIntf,
702 processorErrConfigObjPath);
703
704 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
705 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
706 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
707 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
708 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
709 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
710 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
711 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
712 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
713 }
714 catch (const std::exception& e)
715 {
716 phosphor::logging::log<phosphor::logging::level::ERR>(
717 "Failed to fetch processor error config",
718 phosphor::logging::entry("ERROR=%s", e.what()));
719 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700720 }
721
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700722 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
723 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
724 cpu2Status, cpu3CATERRCount, cpu3Status,
725 cpu4CATERRCount, cpu4Status, crashdumpCount);
726}
Jason M. Bills64796042018-10-03 16:51:55 -0700727
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700728ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
729 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
730 std::optional<bool> clearCPUErrorCount,
731 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
732{
733 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700734
735 try
736 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700737 auto service = ipmi::getService(*busp, processorErrConfigIntf,
738 processorErrConfigObjPath);
739 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
740 processorErrConfigIntf, "ResetOnCATERR",
741 resetOnCATERR);
742 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
743 processorErrConfigIntf, "ResetOnERR2",
744 resetOnERR2);
745 if (clearCPUErrorCount.value_or(false))
746 {
747 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700748 processorErrConfigIntf, "ErrorCountCPU1",
749 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700750 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700751 processorErrConfigIntf, "ErrorCountCPU2",
752 static_cast<uint8_t>(0));
753 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
754 processorErrConfigIntf, "ErrorCountCPU3",
755 static_cast<uint8_t>(0));
756 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
757 processorErrConfigIntf, "ErrorCountCPU4",
758 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700759 }
760 if (clearCrashdumpCount.value_or(false))
761 {
762 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700763 processorErrConfigIntf, "CrashdumpCount",
764 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700765 }
Jason M. Bills64796042018-10-03 16:51:55 -0700766 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700767 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700768 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800769 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700770 "Failed to set processor error config",
771 phosphor::logging::entry("EXCEPTION=%s", e.what()));
772 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700773 }
774
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700775 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700776}
777
Yong Li703922d2018-11-06 13:25:31 +0800778ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
779 ipmi_request_t request,
780 ipmi_response_t response,
781 ipmi_data_len_t dataLen,
782 ipmi_context_t context)
783{
784 GetOEMShutdownPolicyRes* resp =
785 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
786
787 if (*dataLen != 0)
788 {
789 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800790 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800791 *dataLen = 0;
792 return IPMI_CC_REQ_DATA_LEN_INVALID;
793 }
794
795 *dataLen = 0;
796
797 try
798 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700799 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800800 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700801 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
802 Value variant = getDbusProperty(
803 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
804 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800805
806 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
807 convertPolicyFromString(std::get<std::string>(variant)) ==
808 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
809 NoShutdownOnOCOT)
810 {
811 resp->policy = 0;
812 }
813 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
814 convertPolicyFromString(std::get<std::string>(variant)) ==
815 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
816 Policy::ShutdownOnOCOT)
817 {
818 resp->policy = 1;
819 }
820 else
821 {
822 phosphor::logging::log<phosphor::logging::level::ERR>(
823 "oem_set_shutdown_policy: invalid property!",
824 phosphor::logging::entry(
825 "PROP=%s", std::get<std::string>(variant).c_str()));
826 return IPMI_CC_UNSPECIFIED_ERROR;
827 }
Yong Li703922d2018-11-06 13:25:31 +0800828 // TODO needs to check if it is multi-node products,
829 // policy is only supported on node 3/4
830 resp->policySupport = shutdownPolicySupported;
831 }
832 catch (sdbusplus::exception_t& e)
833 {
834 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
835 return IPMI_CC_UNSPECIFIED_ERROR;
836 }
837
838 *dataLen = sizeof(GetOEMShutdownPolicyRes);
839 return IPMI_CC_OK;
840}
841
842ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
843 ipmi_request_t request,
844 ipmi_response_t response,
845 ipmi_data_len_t dataLen,
846 ipmi_context_t context)
847{
848 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800849 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
850 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
851 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800852
853 // TODO needs to check if it is multi-node products,
854 // policy is only supported on node 3/4
855 if (*dataLen != 1)
856 {
857 phosphor::logging::log<phosphor::logging::level::ERR>(
858 "oem_set_shutdown_policy: invalid input len!");
859 *dataLen = 0;
860 return IPMI_CC_REQ_DATA_LEN_INVALID;
861 }
862
863 *dataLen = 0;
864 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
865 {
866 phosphor::logging::log<phosphor::logging::level::ERR>(
867 "oem_set_shutdown_policy: invalid input!");
868 return IPMI_CC_INVALID_FIELD_REQUEST;
869 }
870
Yong Li0669d192019-05-06 14:01:46 +0800871 if (*req == noShutdownOnOCOT)
872 {
873 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
874 Policy::NoShutdownOnOCOT;
875 }
876 else
877 {
878 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
879 Policy::ShutdownOnOCOT;
880 }
881
Yong Li703922d2018-11-06 13:25:31 +0800882 try
883 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700884 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800885 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700886 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800887 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700888 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800889 oemShutdownPolicyObjPathProp,
890 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800891 }
892 catch (sdbusplus::exception_t& e)
893 {
894 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
895 return IPMI_CC_UNSPECIFIED_ERROR;
896 }
897
898 return IPMI_CC_OK;
899}
900
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530901/** @brief implementation for check the DHCP or not in IPv4
902 * @param[in] Channel - Channel number
903 * @returns true or false.
904 */
905static bool isDHCPEnabled(uint8_t Channel)
906{
907 try
908 {
909 auto ethdevice = getChannelName(Channel);
910 if (ethdevice.empty())
911 {
912 return false;
913 }
914 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700915 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530916 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700917 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
918 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530919 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700920 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530921 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
922 {
923 return true;
924 }
925 else
926 {
927 return false;
928 }
929 }
930 catch (sdbusplus::exception_t& e)
931 {
932 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
933 return true;
934 }
935}
936
937/** @brief implementes for check the DHCP or not in IPv6
938 * @param[in] Channel - Channel number
939 * @returns true or false.
940 */
941static bool isDHCPIPv6Enabled(uint8_t Channel)
942{
943
944 try
945 {
946 auto ethdevice = getChannelName(Channel);
947 if (ethdevice.empty())
948 {
949 return false;
950 }
951 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700952 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530953 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700954 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
955 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530956 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700957 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530958 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
959 {
960 return true;
961 }
962 else
963 {
964 return false;
965 }
966 }
967 catch (sdbusplus::exception_t& e)
968 {
969 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
970 return true;
971 }
972}
973
974/** @brief implementes the creating of default new user
975 * @param[in] userName - new username in 16 bytes.
976 * @param[in] userPassword - new password in 20 bytes
977 * @returns ipmi completion code.
978 */
979ipmi::RspType<> ipmiOEMSetUser2Activation(
980 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
981 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
982{
983 bool userState = false;
984 // Check for System Interface not exist and LAN should be static
985 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
986 {
987 ChannelInfo chInfo;
988 try
989 {
990 getChannelInfo(channel, chInfo);
991 }
992 catch (sdbusplus::exception_t& e)
993 {
994 phosphor::logging::log<phosphor::logging::level::ERR>(
995 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
996 phosphor::logging::entry("MSG: %s", e.description()));
997 return ipmi::response(ipmi::ccUnspecifiedError);
998 }
999 if (chInfo.mediumType ==
1000 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1001 {
1002 phosphor::logging::log<phosphor::logging::level::ERR>(
1003 "ipmiOEMSetUser2Activation: system interface exist .");
1004 return ipmi::response(ipmi::ccCommandNotAvailable);
1005 }
1006 else
1007 {
1008
1009 if (chInfo.mediumType ==
1010 static_cast<uint8_t>(EChannelMediumType::lan8032))
1011 {
1012 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1013 {
1014 phosphor::logging::log<phosphor::logging::level::ERR>(
1015 "ipmiOEMSetUser2Activation: DHCP enabled .");
1016 return ipmi::response(ipmi::ccCommandNotAvailable);
1017 }
1018 }
1019 }
1020 }
1021 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1022 if (ipmi::ccSuccess ==
1023 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1024 {
1025 if (enabledUsers > 1)
1026 {
1027 phosphor::logging::log<phosphor::logging::level::ERR>(
1028 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1029 return ipmi::response(ipmi::ccCommandNotAvailable);
1030 }
1031 // Check the user 2 is enabled or not
1032 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1033 if (userState == true)
1034 {
1035 phosphor::logging::log<phosphor::logging::level::ERR>(
1036 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1037 return ipmi::response(ipmi::ccCommandNotAvailable);
1038 }
1039 }
1040 else
1041 {
1042 return ipmi::response(ipmi::ccUnspecifiedError);
1043 }
1044
1045#if BYTE_ORDER == LITTLE_ENDIAN
1046 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1047#endif
1048#if BYTE_ORDER == BIG_ENDIAN
1049 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1050#endif
1051
1052 if (ipmi::ccSuccess ==
1053 ipmiUserSetUserName(ipmiDefaultUserId,
1054 reinterpret_cast<const char*>(userName.data())))
1055 {
1056 if (ipmi::ccSuccess ==
1057 ipmiUserSetUserPassword(
1058 ipmiDefaultUserId,
1059 reinterpret_cast<const char*>(userPassword.data())))
1060 {
1061 if (ipmi::ccSuccess ==
1062 ipmiUserSetPrivilegeAccess(
1063 ipmiDefaultUserId,
1064 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1065 privAccess, true))
1066 {
1067 phosphor::logging::log<phosphor::logging::level::INFO>(
1068 "ipmiOEMSetUser2Activation: user created successfully ");
1069 return ipmi::responseSuccess();
1070 }
1071 }
1072 // we need to delete the default user id which added in this command as
1073 // password / priv setting is failed.
1074 ipmiUserSetUserName(ipmiDefaultUserId, "");
1075 phosphor::logging::log<phosphor::logging::level::ERR>(
1076 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1077 }
1078 else
1079 {
1080 phosphor::logging::log<phosphor::logging::level::ERR>(
1081 "ipmiOEMSetUser2Activation: Setting username failed.");
1082 }
1083
1084 return ipmi::response(ipmi::ccCommandNotAvailable);
1085}
1086
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301087/** @brief implementes setting password for special user
1088 * @param[in] specialUserIndex
1089 * @param[in] userPassword - new password in 20 bytes
1090 * @returns ipmi completion code.
1091 */
1092ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1093 uint8_t specialUserIndex,
1094 std::vector<uint8_t> userPassword)
1095{
1096 ChannelInfo chInfo;
1097 try
1098 {
1099 getChannelInfo(ctx->channel, chInfo);
1100 }
1101 catch (sdbusplus::exception_t& e)
1102 {
1103 phosphor::logging::log<phosphor::logging::level::ERR>(
1104 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1105 phosphor::logging::entry("MSG: %s", e.description()));
1106 return ipmi::responseUnspecifiedError();
1107 }
1108 if (chInfo.mediumType !=
1109 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1110 {
1111 phosphor::logging::log<phosphor::logging::level::ERR>(
1112 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1113 "interface");
1114 return ipmi::responseCommandNotAvailable();
1115 }
1116 if (specialUserIndex != 0)
1117 {
1118 phosphor::logging::log<phosphor::logging::level::ERR>(
1119 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1120 return ipmi::responseParmOutOfRange();
1121 }
1122 constexpr uint8_t minPasswordSizeRequired = 6;
1123 if (userPassword.size() < minPasswordSizeRequired ||
1124 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1125 {
1126 return ipmi::responseReqDataLenInvalid();
1127 }
1128 std::string passwd;
1129 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1130 userPassword.size());
1131 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
1132}
1133
Kuiying Wang45f04982018-12-26 09:23:08 +08001134namespace ledAction
1135{
1136using namespace sdbusplus::xyz::openbmc_project::Led::server;
1137std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
1138 {Physical::Action::Off, 0x00},
1139 {Physical::Action::On, 0x10},
1140 {Physical::Action::Blink, 0x01}};
1141
1142std::map<uint8_t, std::string> offsetObjPath = {
1143 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1144
1145} // namespace ledAction
1146
1147int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1148 const std::string& objPath, uint8_t& state)
1149{
1150 try
1151 {
1152 std::string service = getService(bus, intf, objPath);
1153 Value stateValue =
1154 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001155 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001156 state = ledAction::actionDbusToIpmi.at(
1157 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1158 convertActionFromString(strState));
1159 }
1160 catch (sdbusplus::exception::SdBusError& e)
1161 {
1162 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1163 return -1;
1164 }
1165 return 0;
1166}
1167
1168ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1169 ipmi_request_t request, ipmi_response_t response,
1170 ipmi_data_len_t dataLen, ipmi_context_t context)
1171{
1172 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1173 // LED Status
1174 //[1:0] = Reserved
1175 //[3:2] = Status(Amber)
1176 //[5:4] = Status(Green)
1177 //[7:6] = System Identify
1178 // Status definitions:
1179 // 00b = Off
1180 // 01b = Blink
1181 // 10b = On
1182 // 11b = invalid
1183 if (*dataLen != 0)
1184 {
1185 phosphor::logging::log<phosphor::logging::level::ERR>(
1186 "oem_get_led_status: invalid input len!");
1187 *dataLen = 0;
1188 return IPMI_CC_REQ_DATA_LEN_INVALID;
1189 }
1190
1191 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1192 *resp = 0;
1193 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001194 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001195 for (auto it = ledAction::offsetObjPath.begin();
1196 it != ledAction::offsetObjPath.end(); ++it)
1197 {
1198 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001199 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001200 {
1201 phosphor::logging::log<phosphor::logging::level::ERR>(
1202 "oem_get_led_status: fail to get ID LED status!");
1203 return IPMI_CC_UNSPECIFIED_ERROR;
1204 }
1205 *resp |= state << it->first;
1206 }
1207
1208 *dataLen = sizeof(*resp);
1209 return IPMI_CC_OK;
1210}
1211
Yong Li23737fe2019-02-19 08:49:55 +08001212ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1213 ipmi_request_t request,
1214 ipmi_response_t response,
1215 ipmi_data_len_t dataLen,
1216 ipmi_context_t context)
1217{
1218 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1219 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1220
1221 if (*dataLen == 0)
1222 {
1223 phosphor::logging::log<phosphor::logging::level::ERR>(
1224 "CfgHostSerial: invalid input len!",
1225 phosphor::logging::entry("LEN=%d", *dataLen));
1226 return IPMI_CC_REQ_DATA_LEN_INVALID;
1227 }
1228
1229 switch (req->command)
1230 {
1231 case getHostSerialCfgCmd:
1232 {
1233 if (*dataLen != 1)
1234 {
1235 phosphor::logging::log<phosphor::logging::level::ERR>(
1236 "CfgHostSerial: invalid input len!");
1237 *dataLen = 0;
1238 return IPMI_CC_REQ_DATA_LEN_INVALID;
1239 }
1240
1241 *dataLen = 0;
1242
1243 boost::process::ipstream is;
1244 std::vector<std::string> data;
1245 std::string line;
1246 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1247 boost::process::std_out > is);
1248
1249 while (c1.running() && std::getline(is, line) && !line.empty())
1250 {
1251 data.push_back(line);
1252 }
1253
1254 c1.wait();
1255 if (c1.exit_code())
1256 {
1257 phosphor::logging::log<phosphor::logging::level::ERR>(
1258 "CfgHostSerial:: error on execute",
1259 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1260 // Using the default value
1261 *resp = 0;
1262 }
1263 else
1264 {
1265 if (data.size() != 1)
1266 {
1267 phosphor::logging::log<phosphor::logging::level::ERR>(
1268 "CfgHostSerial:: error on read env");
1269 return IPMI_CC_UNSPECIFIED_ERROR;
1270 }
1271 try
1272 {
1273 unsigned long tmp = std::stoul(data[0]);
1274 if (tmp > std::numeric_limits<uint8_t>::max())
1275 {
1276 throw std::out_of_range("Out of range");
1277 }
1278 *resp = static_cast<uint8_t>(tmp);
1279 }
1280 catch (const std::invalid_argument& e)
1281 {
1282 phosphor::logging::log<phosphor::logging::level::ERR>(
1283 "invalid config ",
1284 phosphor::logging::entry("ERR=%s", e.what()));
1285 return IPMI_CC_UNSPECIFIED_ERROR;
1286 }
1287 catch (const std::out_of_range& e)
1288 {
1289 phosphor::logging::log<phosphor::logging::level::ERR>(
1290 "out_of_range config ",
1291 phosphor::logging::entry("ERR=%s", e.what()));
1292 return IPMI_CC_UNSPECIFIED_ERROR;
1293 }
1294 }
1295
1296 *dataLen = 1;
1297 break;
1298 }
1299 case setHostSerialCfgCmd:
1300 {
1301 if (*dataLen != sizeof(CfgHostSerialReq))
1302 {
1303 phosphor::logging::log<phosphor::logging::level::ERR>(
1304 "CfgHostSerial: invalid input len!");
1305 *dataLen = 0;
1306 return IPMI_CC_REQ_DATA_LEN_INVALID;
1307 }
1308
1309 *dataLen = 0;
1310
1311 if (req->parameter > HostSerialCfgParamMax)
1312 {
1313 phosphor::logging::log<phosphor::logging::level::ERR>(
1314 "CfgHostSerial: invalid input!");
1315 return IPMI_CC_INVALID_FIELD_REQUEST;
1316 }
1317
1318 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1319 std::to_string(req->parameter));
1320
1321 c1.wait();
1322 if (c1.exit_code())
1323 {
1324 phosphor::logging::log<phosphor::logging::level::ERR>(
1325 "CfgHostSerial:: error on execute",
1326 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1327 return IPMI_CC_UNSPECIFIED_ERROR;
1328 }
1329 break;
1330 }
1331 default:
1332 phosphor::logging::log<phosphor::logging::level::ERR>(
1333 "CfgHostSerial: invalid input!");
1334 *dataLen = 0;
1335 return IPMI_CC_INVALID_FIELD_REQUEST;
1336 }
1337
1338 return IPMI_CC_OK;
1339}
1340
James Feist91244a62019-02-19 15:04:54 -08001341constexpr const char* thermalModeInterface =
1342 "xyz.openbmc_project.Control.ThermalMode";
1343constexpr const char* thermalModePath =
1344 "/xyz/openbmc_project/control/thermal_mode";
1345
1346bool getFanProfileInterface(
1347 sdbusplus::bus::bus& bus,
1348 boost::container::flat_map<
1349 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1350{
1351 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1352 "GetAll");
1353 call.append(thermalModeInterface);
1354 try
1355 {
1356 auto data = bus.call(call);
1357 data.read(resp);
1358 }
1359 catch (sdbusplus::exception_t& e)
1360 {
1361 phosphor::logging::log<phosphor::logging::level::ERR>(
1362 "getFanProfileInterface: can't get thermal mode!",
1363 phosphor::logging::entry("ERR=%s", e.what()));
1364 return false;
1365 }
1366 return true;
1367}
1368
anil kumar appanaf945eee2019-09-25 23:29:11 +00001369/**@brief implements the OEM set fan config.
1370 * @param selectedFanProfile - fan profile to enable
1371 * @param reserved1
1372 * @param performanceMode - Performance/Acoustic mode
1373 * @param reserved2
1374 * @param setPerformanceMode - set Performance/Acoustic mode
1375 * @param setFanProfile - set fan profile
1376 *
1377 * @return IPMI completion code.
1378 **/
1379ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1380
1381 uint2_t reserved1, bool performanceMode,
1382 uint3_t reserved2, bool setPerformanceMode,
1383 bool setFanProfile)
James Feist91244a62019-02-19 15:04:54 -08001384{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001385 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001386 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001387 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001388 }
James Feist91244a62019-02-19 15:04:54 -08001389 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001390 boost::container::flat_map<
1391 std::string, std::variant<std::vector<std::string>, std::string>>
1392 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001393 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1394 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001395 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001396 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001397 }
1398
1399 std::vector<std::string>* supported =
1400 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1401 if (supported == nullptr)
1402 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001403 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001404 }
1405 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001406 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001407 {
James Feist91244a62019-02-19 15:04:54 -08001408 if (performanceMode)
1409 {
1410
1411 if (std::find(supported->begin(), supported->end(),
1412 "Performance") != supported->end())
1413 {
1414 mode = "Performance";
1415 }
1416 }
1417 else
1418 {
James Feist91244a62019-02-19 15:04:54 -08001419 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1420 supported->end())
1421 {
1422 mode = "Acoustic";
1423 }
1424 }
1425 if (mode.empty())
1426 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001427 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001428 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001429
1430 try
1431 {
1432 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1433 thermalModeInterface, "Current", mode);
1434 }
1435 catch (sdbusplus::exception_t& e)
1436 {
1437 phosphor::logging::log<phosphor::logging::level::ERR>(
1438 "ipmiOEMSetFanConfig: can't set thermal mode!",
1439 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1440 return ipmi::responseResponseError();
1441 }
James Feist91244a62019-02-19 15:04:54 -08001442 }
1443
anil kumar appanaf945eee2019-09-25 23:29:11 +00001444 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001445}
1446
James Feist5b693632019-07-09 09:06:09 -07001447ipmi::RspType<uint8_t, // profile support map
1448 uint8_t, // fan control profile enable
1449 uint8_t, // flags
1450 uint32_t // dimm presence bit map
1451 >
1452 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001453{
James Feist91244a62019-02-19 15:04:54 -08001454 boost::container::flat_map<
1455 std::string, std::variant<std::vector<std::string>, std::string>>
1456 profileData;
1457
Vernon Mauery15419dd2019-05-24 09:40:30 -07001458 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1459 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001460 {
James Feist5b693632019-07-09 09:06:09 -07001461 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001462 }
1463
1464 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1465
1466 if (current == nullptr)
1467 {
1468 phosphor::logging::log<phosphor::logging::level::ERR>(
1469 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001470 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001471 }
1472 bool performance = (*current == "Performance");
1473
James Feist5b693632019-07-09 09:06:09 -07001474 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001475 if (performance)
1476 {
James Feist5b693632019-07-09 09:06:09 -07001477 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001478 }
1479
James Feist5b693632019-07-09 09:06:09 -07001480 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001481}
James Feist5f957ca2019-03-14 15:33:55 -07001482constexpr const char* cfmLimitSettingPath =
1483 "/xyz/openbmc_project/control/cfm_limit";
1484constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001485constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001486constexpr const size_t legacyPCHSensorNumber = 0x22;
1487constexpr const char* exitAirPathName = "Exit_Air";
1488constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001489constexpr const char* pidConfigurationIface =
1490 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001491
James Feist09f6b602019-08-08 11:30:03 -07001492static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001493{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001494 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001495 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001496 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1497 "/xyz/openbmc_project/object_mapper",
1498 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001499
James Feistacc8a4e2019-04-02 14:23:57 -07001500 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001501 std::string path;
1502 GetSubTreeType resp;
1503 try
1504 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001505 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001506 reply.read(resp);
1507 }
1508 catch (sdbusplus::exception_t&)
1509 {
1510 phosphor::logging::log<phosphor::logging::level::ERR>(
1511 "ipmiOEMGetFscParameter: mapper error");
1512 };
James Feist09f6b602019-08-08 11:30:03 -07001513 auto config =
1514 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1515 return pair.first.find(name) != std::string::npos;
1516 });
James Feistfaa4f222019-03-21 16:21:55 -07001517 if (config != resp.end())
1518 {
1519 path = std::move(config->first);
1520 }
1521 return path;
1522}
James Feist5f957ca2019-03-14 15:33:55 -07001523
James Feistacc8a4e2019-04-02 14:23:57 -07001524// flat map to make alphabetical
1525static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1526{
1527 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001528 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001529 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001530 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1531 "/xyz/openbmc_project/object_mapper",
1532 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001533
1534 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1535 GetSubTreeType resp;
1536
1537 try
1538 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001539 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001540 reply.read(resp);
1541 }
1542 catch (sdbusplus::exception_t&)
1543 {
1544 phosphor::logging::log<phosphor::logging::level::ERR>(
1545 "getFanConfigPaths: mapper error");
1546 };
1547 for (const auto& [path, objects] : resp)
1548 {
1549 if (objects.empty())
1550 {
1551 continue; // should be impossible
1552 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001553
1554 try
1555 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001556 ret.emplace(path,
1557 getAllDbusProperties(*dbus, objects[0].first, path,
1558 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001559 }
1560 catch (sdbusplus::exception_t& e)
1561 {
1562 phosphor::logging::log<phosphor::logging::level::ERR>(
1563 "getPidConfigs: can't get DbusProperties!",
1564 phosphor::logging::entry("ERR=%s", e.what()));
1565 }
James Feistacc8a4e2019-04-02 14:23:57 -07001566 }
1567 return ret;
1568}
1569
1570ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1571{
1572 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1573 if (data.empty())
1574 {
1575 return ipmi::responseResponseError();
1576 }
1577 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1578 for (const auto& [_, pid] : data)
1579 {
1580 auto findClass = pid.find("Class");
1581 if (findClass == pid.end())
1582 {
1583 phosphor::logging::log<phosphor::logging::level::ERR>(
1584 "ipmiOEMGetFscParameter: found illegal pid "
1585 "configurations");
1586 return ipmi::responseResponseError();
1587 }
1588 std::string type = std::get<std::string>(findClass->second);
1589 if (type == "fan")
1590 {
1591 auto findOutLimit = pid.find("OutLimitMin");
1592 if (findOutLimit == pid.end())
1593 {
1594 phosphor::logging::log<phosphor::logging::level::ERR>(
1595 "ipmiOEMGetFscParameter: found illegal pid "
1596 "configurations");
1597 return ipmi::responseResponseError();
1598 }
1599 // get the min out of all the offsets
1600 minOffset = std::min(
1601 minOffset,
1602 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1603 }
1604 }
1605 if (minOffset == std::numeric_limits<uint8_t>::max())
1606 {
1607 phosphor::logging::log<phosphor::logging::level::ERR>(
1608 "ipmiOEMGetFscParameter: found no fan configurations!");
1609 return ipmi::responseResponseError();
1610 }
1611
1612 return ipmi::responseSuccess(minOffset);
1613}
1614
1615ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1616{
1617 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1618 if (data.empty())
1619 {
1620
1621 phosphor::logging::log<phosphor::logging::level::ERR>(
1622 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1623 return ipmi::responseResponseError();
1624 }
1625
Vernon Mauery15419dd2019-05-24 09:40:30 -07001626 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001627 bool found = false;
1628 for (const auto& [path, pid] : data)
1629 {
1630 auto findClass = pid.find("Class");
1631 if (findClass == pid.end())
1632 {
1633
1634 phosphor::logging::log<phosphor::logging::level::ERR>(
1635 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1636 "configurations");
1637 return ipmi::responseResponseError();
1638 }
1639 std::string type = std::get<std::string>(findClass->second);
1640 if (type == "fan")
1641 {
1642 auto findOutLimit = pid.find("OutLimitMin");
1643 if (findOutLimit == pid.end())
1644 {
1645
1646 phosphor::logging::log<phosphor::logging::level::ERR>(
1647 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1648 "configurations");
1649 return ipmi::responseResponseError();
1650 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001651 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001652 path, pidConfigurationIface, "OutLimitMin",
1653 static_cast<double>(offset));
1654 found = true;
1655 }
1656 }
1657 if (!found)
1658 {
1659 phosphor::logging::log<phosphor::logging::level::ERR>(
1660 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1661 return ipmi::responseResponseError();
1662 }
1663
1664 return ipmi::responseSuccess();
1665}
1666
1667ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1668 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001669{
1670 constexpr const size_t disableLimiting = 0x0;
1671
Vernon Mauery15419dd2019-05-24 09:40:30 -07001672 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001673 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001674 {
James Feist09f6b602019-08-08 11:30:03 -07001675 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001676 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001677 {
James Feist09f6b602019-08-08 11:30:03 -07001678 pathName = exitAirPathName;
1679 }
1680 else if (param1 == legacyPCHSensorNumber)
1681 {
1682 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001683 }
1684 else
1685 {
James Feistacc8a4e2019-04-02 14:23:57 -07001686 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001687 }
James Feist09f6b602019-08-08 11:30:03 -07001688 std::string path = getConfigPath(pathName);
1689 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1690 pidConfigurationIface, "SetPoint",
1691 static_cast<double>(param2));
1692 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001693 }
James Feistacc8a4e2019-04-02 14:23:57 -07001694 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001695 {
James Feistacc8a4e2019-04-02 14:23:57 -07001696 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001697
1698 // must be greater than 50 based on eps
1699 if (cfm < 50 && cfm != disableLimiting)
1700 {
James Feistacc8a4e2019-04-02 14:23:57 -07001701 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001702 }
1703
1704 try
1705 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001706 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001707 cfmLimitIface, "Limit",
1708 static_cast<double>(cfm));
1709 }
1710 catch (sdbusplus::exception_t& e)
1711 {
1712 phosphor::logging::log<phosphor::logging::level::ERR>(
1713 "ipmiOEMSetFscParameter: can't set cfm setting!",
1714 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001715 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001716 }
James Feistacc8a4e2019-04-02 14:23:57 -07001717 return ipmi::responseSuccess();
1718 }
1719 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1720 {
1721 constexpr const size_t maxDomainCount = 8;
1722 uint8_t requestedDomainMask = param1;
1723 boost::container::flat_map data = getPidConfigs();
1724 if (data.empty())
1725 {
1726
1727 phosphor::logging::log<phosphor::logging::level::ERR>(
1728 "ipmiOEMSetFscParameter: found no pid configurations!");
1729 return ipmi::responseResponseError();
1730 }
1731 size_t count = 0;
1732 for (const auto& [path, pid] : data)
1733 {
1734 auto findClass = pid.find("Class");
1735 if (findClass == pid.end())
1736 {
1737
1738 phosphor::logging::log<phosphor::logging::level::ERR>(
1739 "ipmiOEMSetFscParameter: found illegal pid "
1740 "configurations");
1741 return ipmi::responseResponseError();
1742 }
1743 std::string type = std::get<std::string>(findClass->second);
1744 if (type == "fan")
1745 {
1746 if (requestedDomainMask & (1 << count))
1747 {
1748 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001749 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001750 pidConfigurationIface, "OutLimitMax",
1751 static_cast<double>(param2));
1752 }
1753 count++;
1754 }
1755 }
1756 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001757 }
1758 else
1759 {
1760 // todo other command parts possibly
1761 // tcontrol is handled in peci now
1762 // fan speed offset not implemented yet
1763 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001764 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001765 }
1766}
1767
James Feistacc8a4e2019-04-02 14:23:57 -07001768ipmi::RspType<
1769 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1770 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001771{
James Feist09f6b602019-08-08 11:30:03 -07001772 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001773
Vernon Mauery15419dd2019-05-24 09:40:30 -07001774 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001775 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001776 {
James Feistacc8a4e2019-04-02 14:23:57 -07001777 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001778 {
James Feistacc8a4e2019-04-02 14:23:57 -07001779 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001780 }
1781
James Feist09f6b602019-08-08 11:30:03 -07001782 std::string pathName;
1783
1784 if (*param == legacyExitAirSensorNumber)
1785 {
1786 pathName = exitAirPathName;
1787 }
1788 else if (*param == legacyPCHSensorNumber)
1789 {
1790 pathName = pchPathName;
1791 }
1792 else
James Feistfaa4f222019-03-21 16:21:55 -07001793 {
James Feistacc8a4e2019-04-02 14:23:57 -07001794 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001795 }
James Feist09f6b602019-08-08 11:30:03 -07001796
1797 uint8_t setpoint = legacyDefaultSetpoint;
1798 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001799 if (path.size())
1800 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001801 Value val = ipmi::getDbusProperty(
1802 *dbus, "xyz.openbmc_project.EntityManager", path,
1803 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001804 setpoint = std::floor(std::get<double>(val) + 0.5);
1805 }
1806
1807 // old implementation used to return the "default" and current, we
1808 // don't make the default readily available so just make both the
1809 // same
James Feistfaa4f222019-03-21 16:21:55 -07001810
James Feistacc8a4e2019-04-02 14:23:57 -07001811 return ipmi::responseSuccess(
1812 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001813 }
James Feistacc8a4e2019-04-02 14:23:57 -07001814 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1815 {
1816 constexpr const size_t maxDomainCount = 8;
1817
1818 if (!param)
1819 {
1820 return ipmi::responseReqDataLenInvalid();
1821 }
1822 uint8_t requestedDomain = *param;
1823 if (requestedDomain >= maxDomainCount)
1824 {
1825 return ipmi::responseInvalidFieldRequest();
1826 }
1827
1828 boost::container::flat_map data = getPidConfigs();
1829 if (data.empty())
1830 {
1831 phosphor::logging::log<phosphor::logging::level::ERR>(
1832 "ipmiOEMGetFscParameter: found no pid configurations!");
1833 return ipmi::responseResponseError();
1834 }
1835 size_t count = 0;
1836 for (const auto& [_, pid] : data)
1837 {
1838 auto findClass = pid.find("Class");
1839 if (findClass == pid.end())
1840 {
1841 phosphor::logging::log<phosphor::logging::level::ERR>(
1842 "ipmiOEMGetFscParameter: found illegal pid "
1843 "configurations");
1844 return ipmi::responseResponseError();
1845 }
1846 std::string type = std::get<std::string>(findClass->second);
1847 if (type == "fan")
1848 {
1849 if (requestedDomain == count)
1850 {
1851 auto findOutLimit = pid.find("OutLimitMax");
1852 if (findOutLimit == pid.end())
1853 {
1854 phosphor::logging::log<phosphor::logging::level::ERR>(
1855 "ipmiOEMGetFscParameter: found illegal pid "
1856 "configurations");
1857 return ipmi::responseResponseError();
1858 }
1859
1860 return ipmi::responseSuccess(
1861 static_cast<uint8_t>(std::floor(
1862 std::get<double>(findOutLimit->second) + 0.5)));
1863 }
1864 else
1865 {
1866 count++;
1867 }
1868 }
1869 }
1870
1871 return ipmi::responseInvalidFieldRequest();
1872 }
1873 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001874 {
1875
1876 /*
1877 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001878 previous behavior didn't seem to prevent this, ignore the check for
1879 now.
James Feist5f957ca2019-03-14 15:33:55 -07001880
James Feistacc8a4e2019-04-02 14:23:57 -07001881 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001882 {
1883 phosphor::logging::log<phosphor::logging::level::ERR>(
1884 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001885 return IPMI_CC_REQ_DATA_LEN_INVALID;
1886 }
1887 */
1888 Value cfmLimit;
1889 Value cfmMaximum;
1890 try
1891 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001892 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001893 cfmLimitSettingPath, cfmLimitIface,
1894 "Limit");
1895 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001896 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001897 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1898 }
1899 catch (sdbusplus::exception_t& e)
1900 {
1901 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001902 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001903 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001904 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001905 }
1906
James Feistacc8a4e2019-04-02 14:23:57 -07001907 double cfmMax = std::get<double>(cfmMaximum);
1908 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001909
James Feistacc8a4e2019-04-02 14:23:57 -07001910 cfmLim = std::floor(cfmLim + 0.5);
1911 cfmMax = std::floor(cfmMax + 0.5);
1912 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1913 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001914
James Feistacc8a4e2019-04-02 14:23:57 -07001915 return ipmi::responseSuccess(
1916 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001917 }
James Feistacc8a4e2019-04-02 14:23:57 -07001918
James Feist5f957ca2019-03-14 15:33:55 -07001919 else
1920 {
1921 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001922 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001923 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001924 }
1925}
1926
Cheng C Yang773703a2019-08-15 09:41:11 +08001927using crConfigVariant =
1928 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
1929
1930int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1931 const crConfigVariant& value,
1932 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1933{
1934 boost::system::error_code ec;
1935 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07001936 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08001937 "/xyz/openbmc_project/control/power_supply_redundancy",
1938 "org.freedesktop.DBus.Properties", "Set",
1939 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
1940 if (ec)
1941 {
1942 phosphor::logging::log<phosphor::logging::level::ERR>(
1943 "Failed to set dbus property to cold redundancy");
1944 return -1;
1945 }
1946
1947 return 0;
1948}
1949
1950int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1951 crConfigVariant& value,
1952 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1953{
1954 boost::system::error_code ec;
1955 value = ctx->bus->yield_method_call<crConfigVariant>(
James Feist28c72902019-09-16 10:34:07 -07001956 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08001957 "/xyz/openbmc_project/control/power_supply_redundancy",
1958 "org.freedesktop.DBus.Properties", "Get",
1959 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
1960 if (ec)
1961 {
1962 phosphor::logging::log<phosphor::logging::level::ERR>(
1963 "Failed to get dbus property to cold redundancy");
1964 return -1;
1965 }
1966 return 0;
1967}
1968
1969uint8_t getPSUCount(void)
1970{
1971 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1972 ipmi::Value num;
1973 try
1974 {
1975 num = ipmi::getDbusProperty(
1976 *dbus, "xyz.openbmc_project.PSURedundancy",
1977 "/xyz/openbmc_project/control/power_supply_redundancy",
1978 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
1979 }
1980 catch (sdbusplus::exception_t& e)
1981 {
1982 phosphor::logging::log<phosphor::logging::level::ERR>(
1983 "Failed to get PSUNumber property from dbus interface");
1984 return 0;
1985 }
1986 uint8_t* pNum = std::get_if<uint8_t>(&num);
1987 if (!pNum)
1988 {
1989 phosphor::logging::log<phosphor::logging::level::ERR>(
1990 "Error to get PSU Number");
1991 return 0;
1992 }
1993 return *pNum;
1994}
1995
1996bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
1997{
1998 if (conf.size() < num)
1999 {
2000 phosphor::logging::log<phosphor::logging::level::ERR>(
2001 "Invalid PSU Ranking");
2002 return false;
2003 }
2004 std::set<uint8_t> confSet;
2005 for (uint8_t i = 0; i < num; i++)
2006 {
2007 if (conf[i] > num)
2008 {
2009 phosphor::logging::log<phosphor::logging::level::ERR>(
2010 "PSU Ranking is larger than current PSU number");
2011 return false;
2012 }
2013 confSet.emplace(conf[i]);
2014 }
2015
2016 if (confSet.size() != num)
2017 {
2018 phosphor::logging::log<phosphor::logging::level::ERR>(
2019 "duplicate PSU Ranking");
2020 return false;
2021 }
2022 return true;
2023}
2024
2025enum class crParameter
2026{
2027 crStatus = 0,
2028 crFeature = 1,
2029 rotationFeature = 2,
2030 rotationAlgo = 3,
2031 rotationPeriod = 4,
2032 numOfPSU = 5
2033};
2034
2035constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2036static const constexpr uint32_t oneDay = 0x15180;
2037static const constexpr uint32_t oneMonth = 0xf53700;
2038static const constexpr uint8_t userSpecific = 0x01;
2039static const constexpr uint8_t crSetCompleted = 0;
2040ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2041 uint8_t parameter,
2042 ipmi::message::Payload& payload)
2043{
2044 switch (static_cast<crParameter>(parameter))
2045 {
2046 case crParameter::crFeature:
2047 {
2048 uint8_t param1;
2049 if (payload.unpack(param1) || !payload.fullyUnpacked())
2050 {
2051 return ipmi::responseReqDataLenInvalid();
2052 }
2053 // ColdRedundancy Enable can only be true or flase
2054 if (param1 > 1)
2055 {
2056 return ipmi::responseInvalidFieldRequest();
2057 }
2058 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2059 static_cast<bool>(param1)))
2060 {
2061 return ipmi::responseResponseError();
2062 }
2063 break;
2064 }
2065 case crParameter::rotationFeature:
2066 {
2067 uint8_t param1;
2068 if (payload.unpack(param1) || !payload.fullyUnpacked())
2069 {
2070 return ipmi::responseReqDataLenInvalid();
2071 }
2072 // Rotation Enable can only be true or false
2073 if (param1 > 1)
2074 {
2075 return ipmi::responseInvalidFieldRequest();
2076 }
2077 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2078 {
2079 return ipmi::responseResponseError();
2080 }
2081 break;
2082 }
2083 case crParameter::rotationAlgo:
2084 {
2085 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2086 std::string algoName;
2087 uint8_t param1;
2088 if (payload.unpack(param1))
2089 {
2090 return ipmi::responseReqDataLenInvalid();
2091 }
2092 switch (param1)
2093 {
2094 case 0:
2095 algoName = "xyz.openbmc_project.Control."
2096 "PowerSupplyRedundancy.Algo.bmcSpecific";
2097 break;
2098 case 1:
2099 algoName = "xyz.openbmc_project.Control."
2100 "PowerSupplyRedundancy.Algo.userSpecific";
2101 break;
2102 default:
2103 return ipmi::responseInvalidFieldRequest();
2104 }
2105 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2106 {
2107 return ipmi::responseResponseError();
2108 }
2109
2110 uint8_t numberOfPSU = getPSUCount();
2111 if (!numberOfPSU)
2112 {
2113 return ipmi::responseResponseError();
2114 }
2115 std::vector<uint8_t> rankOrder;
2116
2117 if (param1 == userSpecific)
2118 {
2119 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2120 {
2121 ipmi::responseReqDataLenInvalid();
2122 }
Yong Li83315132019-10-23 17:42:24 +08002123 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002124 {
2125 return ipmi::responseReqDataLenInvalid();
2126 }
2127
2128 if (!validateCRAlgo(rankOrder, numberOfPSU))
2129 {
2130 return ipmi::responseInvalidFieldRequest();
2131 }
2132 }
2133 else
2134 {
2135 if (rankOrder.size() > 0)
2136 {
2137 return ipmi::responseReqDataLenInvalid();
2138 }
2139 for (uint8_t i = 1; i <= numberOfPSU; i++)
2140 {
2141 rankOrder.emplace_back(i);
2142 }
2143 }
2144 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2145 {
2146 return ipmi::responseResponseError();
2147 }
2148 break;
2149 }
2150 case crParameter::rotationPeriod:
2151 {
2152 // Minimum Rotation period is One day (86400 seconds) and Max
2153 // Rotation Period is 6 month (0xf53700 seconds)
2154 uint32_t period;
2155 if (payload.unpack(period) || !payload.fullyUnpacked())
2156 {
2157 return ipmi::responseReqDataLenInvalid();
2158 }
2159 if ((period < oneDay) || (period > oneMonth))
2160 {
2161 return ipmi::responseInvalidFieldRequest();
2162 }
2163 if (setCRConfig(ctx, "PeriodOfRotation", period))
2164 {
2165 return ipmi::responseResponseError();
2166 }
2167 break;
2168 }
2169 default:
2170 {
2171 return ipmi::response(ccParameterNotSupported);
2172 }
2173 }
2174
2175 // TODO Halfwidth needs to set SetInProgress
2176 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002177 std::string("xyz.openbmc_project.Control."
2178 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002179 {
2180 return ipmi::responseResponseError();
2181 }
2182 return ipmi::responseSuccess(crSetCompleted);
2183}
2184
Yong Li83315132019-10-23 17:42:24 +08002185ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002186 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2187{
2188 crConfigVariant value;
2189 switch (static_cast<crParameter>(parameter))
2190 {
2191 case crParameter::crStatus:
2192 {
2193 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2194 {
2195 return ipmi::responseResponseError();
2196 }
2197 std::string* pStatus = std::get_if<std::string>(&value);
2198 if (!pStatus)
2199 {
2200 phosphor::logging::log<phosphor::logging::level::ERR>(
2201 "Error to get ColdRedundancyStatus property");
2202 return ipmi::responseResponseError();
2203 }
2204 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2205 auto status =
2206 server::PowerSupplyRedundancy::convertStatusFromString(
2207 *pStatus);
2208 switch (status)
2209 {
2210 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002211 return ipmi::responseSuccess(parameter,
2212 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002213
2214 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002215 return ipmi::responseSuccess(parameter,
2216 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002217 default:
2218 phosphor::logging::log<phosphor::logging::level::ERR>(
2219 "Error to get valid status");
2220 return ipmi::responseResponseError();
2221 }
2222 }
2223 case crParameter::crFeature:
2224 {
2225 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2226 {
2227 return ipmi::responseResponseError();
2228 }
2229 bool* pResponse = std::get_if<bool>(&value);
2230 if (!pResponse)
2231 {
2232 phosphor::logging::log<phosphor::logging::level::ERR>(
2233 "Error to get ColdRedundancyEnable property");
2234 return ipmi::responseResponseError();
2235 }
2236
Cheng C Yangf41e3342019-09-10 04:47:23 +08002237 return ipmi::responseSuccess(parameter,
2238 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002239 }
2240 case crParameter::rotationFeature:
2241 {
2242 if (getCRConfig(ctx, "RotationEnabled", value))
2243 {
2244 return ipmi::responseResponseError();
2245 }
2246 bool* pResponse = std::get_if<bool>(&value);
2247 if (!pResponse)
2248 {
2249 phosphor::logging::log<phosphor::logging::level::ERR>(
2250 "Error to get RotationEnabled property");
2251 return ipmi::responseResponseError();
2252 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002253 return ipmi::responseSuccess(parameter,
2254 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002255 }
2256 case crParameter::rotationAlgo:
2257 {
2258 if (getCRConfig(ctx, "RotationAlgorithm", value))
2259 {
2260 return ipmi::responseResponseError();
2261 }
2262
2263 std::string* pAlgo = std::get_if<std::string>(&value);
2264 if (!pAlgo)
2265 {
2266 phosphor::logging::log<phosphor::logging::level::ERR>(
2267 "Error to get RotationAlgorithm property");
2268 return ipmi::responseResponseError();
2269 }
Yong Li83315132019-10-23 17:42:24 +08002270 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002271 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2272 auto algo =
2273 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002274
Cheng C Yang773703a2019-08-15 09:41:11 +08002275 switch (algo)
2276 {
2277 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002278 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002279 break;
2280 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002281 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002282 break;
2283 default:
2284 phosphor::logging::log<phosphor::logging::level::ERR>(
2285 "Error to get valid algo");
2286 return ipmi::responseResponseError();
2287 }
2288
2289 if (getCRConfig(ctx, "RotationRankOrder", value))
2290 {
2291 return ipmi::responseResponseError();
2292 }
2293 std::vector<uint8_t>* pResponse =
2294 std::get_if<std::vector<uint8_t>>(&value);
2295 if (!pResponse)
2296 {
2297 phosphor::logging::log<phosphor::logging::level::ERR>(
2298 "Error to get RotationRankOrder property");
2299 return ipmi::responseResponseError();
2300 }
Yong Li83315132019-10-23 17:42:24 +08002301
Cheng C Yang773703a2019-08-15 09:41:11 +08002302 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002303 std::back_inserter(response));
2304
Cheng C Yangf41e3342019-09-10 04:47:23 +08002305 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002306 }
2307 case crParameter::rotationPeriod:
2308 {
2309 if (getCRConfig(ctx, "PeriodOfRotation", value))
2310 {
2311 return ipmi::responseResponseError();
2312 }
2313 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2314 if (!pResponse)
2315 {
2316 phosphor::logging::log<phosphor::logging::level::ERR>(
2317 "Error to get RotationAlgorithm property");
2318 return ipmi::responseResponseError();
2319 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002320 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002321 }
2322 case crParameter::numOfPSU:
2323 {
2324 uint8_t numberOfPSU = getPSUCount();
2325 if (!numberOfPSU)
2326 {
2327 return ipmi::responseResponseError();
2328 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002329 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002330 }
2331 default:
2332 {
2333 return ipmi::response(ccParameterNotSupported);
2334 }
2335 }
2336}
2337
Zhu, Yungebe560b02019-04-21 21:19:21 -04002338ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2339 uint8_t faultState,
2340 uint8_t faultGroup,
2341 std::array<uint8_t, 8>& ledStateData)
2342{
2343 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2344 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2345 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2346 static const std::array<std::string, maxFaultType> faultNames = {
2347 "faultFan", "faultTemp", "faultPower",
2348 "faultDriveSlot", "faultSoftware", "faultMemory"};
2349 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2350 static constexpr const char* postfixValue = "/value";
2351
2352 constexpr uint8_t maxFaultSource = 0x4;
2353 constexpr uint8_t skipLEDs = 0xFF;
2354 constexpr uint8_t pinSize = 64;
2355 constexpr uint8_t groupSize = 16;
2356
2357 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2358 uint64_t resFIndex = 0;
2359 std::string resFType;
2360 std::string service;
2361 ObjectValueTree valueTree;
2362
2363 // Validate the source, fault type
2364 if ((sourceId >= maxFaultSource) ||
2365 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2366 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2367 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2368 {
2369 return ipmi::responseParmOutOfRange();
2370 }
2371
Vernon Mauery15419dd2019-05-24 09:40:30 -07002372 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002373 try
2374 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002375 service = getService(*dbus, intf, objpath);
2376 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002377 }
2378 catch (const std::exception& e)
2379 {
2380 phosphor::logging::log<phosphor::logging::level::ERR>(
2381 "No object implements interface",
2382 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2383 phosphor::logging::entry("INTF=%s", intf));
2384 return ipmi::responseResponseError();
2385 }
2386
2387 if (valueTree.empty())
2388 {
2389 phosphor::logging::log<phosphor::logging::level::ERR>(
2390 "No object implements interface",
2391 phosphor::logging::entry("INTF=%s", intf));
2392 return ipmi::responseResponseError();
2393 }
2394
2395 for (const auto& item : valueTree)
2396 {
2397 // find LedFault configuration
2398 auto interface =
2399 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2400 if (interface == item.second.end())
2401 {
2402 continue;
2403 }
2404
2405 // find matched fault type: faultMemmory / faultFan
2406 // find LedGpioPins/FaultIndex configuration
2407 auto propertyFaultType = interface->second.find("FaultType");
2408 auto propertyFIndex = interface->second.find("FaultIndex");
2409 auto ledIndex = interface->second.find("LedGpioPins");
2410
2411 if (propertyFaultType == interface->second.end() ||
2412 propertyFIndex == interface->second.end() ||
2413 ledIndex == interface->second.end())
2414 {
2415 continue;
2416 }
2417
2418 try
2419 {
2420 Value valIndex = propertyFIndex->second;
2421 resFIndex = std::get<uint64_t>(valIndex);
2422
2423 Value valFType = propertyFaultType->second;
2424 resFType = std::get<std::string>(valFType);
2425 }
2426 catch (const std::bad_variant_access& e)
2427 {
2428 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2429 return ipmi::responseResponseError();
2430 }
2431 // find the matched requested fault type: faultMemmory or faultFan
2432 if (resFType != faultNames[faultType])
2433 {
2434 continue;
2435 }
2436
2437 // read LedGpioPins data
2438 std::vector<uint64_t> ledgpios;
2439 std::variant<std::vector<uint64_t>> message;
2440
Vernon Mauery15419dd2019-05-24 09:40:30 -07002441 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002442 service.c_str(), (std::string(item.first)).c_str(),
2443 "org.freedesktop.DBus.Properties", "Get");
2444
2445 method.append("xyz.openbmc_project.Configuration.LedFault",
2446 "LedGpioPins");
2447
2448 try
2449 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002450 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002451 reply.read(message);
2452 ledgpios = std::get<std::vector<uint64_t>>(message);
2453 }
2454 catch (std::exception& e)
2455 {
2456 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2457 return ipmi::responseResponseError();
2458 }
2459
2460 // Check the size to be sure it will never overflow on groupSize
2461 if (ledgpios.size() > groupSize)
2462 {
2463 phosphor::logging::log<phosphor::logging::level::ERR>(
2464 "Fault gpio Pins out of range!");
2465 return ipmi::responseParmOutOfRange();
2466 }
2467 // Store data, according to command data bit index order
2468 for (int i = 0; i < ledgpios.size(); i++)
2469 {
2470 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2471 }
2472 }
2473
2474 switch (RemoteFaultType(faultType))
2475 {
2476 case (RemoteFaultType::fan):
2477 case (RemoteFaultType::memory):
2478 {
2479 if (faultGroup == skipLEDs)
2480 {
2481 return ipmi::responseSuccess();
2482 }
2483
2484 uint64_t ledState = 0;
2485 // calculate led state bit filed count, each byte has 8bits
2486 // the maximum bits will be 8 * 8 bits
2487 constexpr uint8_t size = sizeof(ledStateData) * 8;
2488 for (int i = 0; i < sizeof(ledStateData); i++)
2489 {
2490 ledState = (uint64_t)(ledState << 8);
2491 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2492 }
2493
2494 std::bitset<size> ledStateBits(ledState);
2495 std::string gpioValue;
2496 for (int i = 0; i < size; i++)
2497 { // skip invalid value
2498 if (ledFaultPins[i] == 0xFFFF)
2499 {
2500 continue;
2501 }
2502
2503 std::string device = sysGpioPath +
2504 std::to_string(ledFaultPins[i]) +
2505 postfixValue;
2506 std::fstream gpioFile;
2507
2508 gpioFile.open(device, std::ios::out);
2509
2510 if (!gpioFile.good())
2511 {
2512 phosphor::logging::log<phosphor::logging::level::ERR>(
2513 "Not Find Led Gpio Device!",
2514 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2515 return ipmi::responseResponseError();
2516 }
2517 gpioFile << std::to_string(
2518 static_cast<uint8_t>(ledStateBits[i]));
2519 gpioFile.close();
2520 }
2521 break;
2522 }
2523 default:
2524 {
2525 // now only support two fault types
2526 return ipmi::responseParmOutOfRange();
2527 }
2528 }
2529
2530 return ipmi::responseSuccess();
2531}
2532
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302533ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2534{
2535 uint8_t prodId = 0;
2536 try
2537 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002538 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302539 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002540 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302541 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2542 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002543 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302544 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2545 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2546 }
2547 catch (std::exception& e)
2548 {
2549 phosphor::logging::log<phosphor::logging::level::ERR>(
2550 "ipmiOEMReadBoardProductId: Product ID read failed!",
2551 phosphor::logging::entry("ERR=%s", e.what()));
2552 }
2553 return ipmi::responseSuccess(prodId);
2554}
2555
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302556/** @brief implements the get security mode command
2557 * @param ctx - ctx pointer
2558 *
2559 * @returns IPMI completion code with following data
2560 * - restriction mode value - As specified in
2561 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2562 * - special mode value - As specified in
2563 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2564 */
2565ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2566{
2567 namespace securityNameSpace =
2568 sdbusplus::xyz::openbmc_project::Control::Security::server;
2569 uint8_t restrictionModeValue = 0;
2570 uint8_t specialModeValue = 0;
2571
2572 boost::system::error_code ec;
2573 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002574 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302575 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2576 restricionModeProperty);
2577 if (ec)
2578 {
2579 phosphor::logging::log<phosphor::logging::level::ERR>(
2580 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2581 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2582 return ipmi::responseUnspecifiedError();
2583 }
2584 restrictionModeValue = static_cast<uint8_t>(
2585 securityNameSpace::RestrictionMode::convertModesFromString(
2586 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302587 auto varSpecialMode =
2588 ctx->bus->yield_method_call<std::variant<std::string>>(
2589 ctx->yield, ec, specialModeService, specialModeBasePath,
2590 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2591 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302592 if (ec)
2593 {
2594 phosphor::logging::log<phosphor::logging::level::ERR>(
2595 "ipmiGetSecurityMode: failed to get SpecialMode property",
2596 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2597 // fall through, let us not worry about SpecialMode property, which is
2598 // not required in user scenario
2599 }
2600 else
2601 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302602 specialModeValue = static_cast<uint8_t>(
2603 securityNameSpace::SpecialMode::convertModesFromString(
2604 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302605 }
2606 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2607}
2608
2609/** @brief implements the set security mode command
2610 * Command allows to upgrade the restriction mode and won't allow
2611 * to downgrade from system interface
2612 * @param ctx - ctx pointer
2613 * @param restrictionMode - restriction mode value to be set.
2614 *
2615 * @returns IPMI completion code
2616 */
2617ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302618 uint8_t restrictionMode,
2619 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302620{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302621#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2622 if (specialMode)
2623 {
2624 return ipmi::responseReqDataLenInvalid();
2625 }
2626#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302627 namespace securityNameSpace =
2628 sdbusplus::xyz::openbmc_project::Control::Security::server;
2629
2630 ChannelInfo chInfo;
2631 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2632 {
2633 phosphor::logging::log<phosphor::logging::level::ERR>(
2634 "ipmiSetSecurityMode: Failed to get Channel Info",
2635 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2636 return ipmi::responseUnspecifiedError();
2637 }
2638 auto reqMode =
2639 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2640
2641 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2642 (reqMode >
2643 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2644 {
2645 return ipmi::responseInvalidFieldRequest();
2646 }
2647
2648 boost::system::error_code ec;
2649 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002650 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302651 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2652 restricionModeProperty);
2653 if (ec)
2654 {
2655 phosphor::logging::log<phosphor::logging::level::ERR>(
2656 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2657 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2658 return ipmi::responseUnspecifiedError();
2659 }
2660 auto currentRestrictionMode =
2661 securityNameSpace::RestrictionMode::convertModesFromString(
2662 std::get<std::string>(varRestrMode));
2663
2664 if (chInfo.mediumType !=
2665 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2666 currentRestrictionMode > reqMode)
2667 {
2668 phosphor::logging::log<phosphor::logging::level::ERR>(
2669 "ipmiSetSecurityMode - Downgrading security mode not supported "
2670 "through system interface",
2671 phosphor::logging::entry(
2672 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2673 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2674 return ipmi::responseCommandNotAvailable();
2675 }
2676
2677 ec.clear();
2678 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002679 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302680 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2681 restricionModeProperty,
2682 static_cast<std::variant<std::string>>(
2683 securityNameSpace::convertForMessage(reqMode)));
2684
2685 if (ec)
2686 {
2687 phosphor::logging::log<phosphor::logging::level::ERR>(
2688 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2689 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2690 return ipmi::responseUnspecifiedError();
2691 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302692
2693#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2694 if (specialMode)
2695 {
2696 ec.clear();
2697 ctx->bus->yield_method_call<>(
2698 ctx->yield, ec, specialModeService, specialModeBasePath,
2699 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2700 specialModeProperty,
2701 static_cast<std::variant<std::string>>(
2702 securityNameSpace::convertForMessage(
2703 static_cast<securityNameSpace::SpecialMode::Modes>(
2704 specialMode.value()))));
2705
2706 if (ec)
2707 {
2708 phosphor::logging::log<phosphor::logging::level::ERR>(
2709 "ipmiSetSecurityMode: failed to set SpecialMode property",
2710 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2711 return ipmi::responseUnspecifiedError();
2712 }
2713 }
2714#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302715 return ipmi::responseSuccess();
2716}
2717
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002718ipmi::RspType<uint8_t /* restore status */>
2719 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2720{
2721 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2722
2723 if (clr != expClr)
2724 {
2725 return ipmi::responseInvalidFieldRequest();
2726 }
2727 constexpr uint8_t cmdStatus = 0;
2728 constexpr uint8_t cmdDefaultRestore = 0xaa;
2729 constexpr uint8_t cmdFullRestore = 0xbb;
2730 constexpr uint8_t cmdFormat = 0xcc;
2731
2732 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2733
2734 switch (cmd)
2735 {
2736 case cmdStatus:
2737 break;
2738 case cmdDefaultRestore:
2739 case cmdFullRestore:
2740 case cmdFormat:
2741 {
2742 // write file to rwfs root
2743 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2744 std::ofstream restoreFile(restoreOpFname);
2745 if (!restoreFile)
2746 {
2747 return ipmi::responseUnspecifiedError();
2748 }
2749 restoreFile << value << "\n";
2750 break;
2751 }
2752 default:
2753 return ipmi::responseInvalidFieldRequest();
2754 }
2755
2756 constexpr uint8_t restorePending = 0;
2757 constexpr uint8_t restoreComplete = 1;
2758
2759 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2760 ? restorePending
2761 : restoreComplete;
2762 return ipmi::responseSuccess(restoreStatus);
2763}
2764
Chen Yugang39736d52019-07-12 16:24:33 +08002765ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2766{
2767 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002768 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002769
2770 try
2771 {
2772 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2773 std::string service =
2774 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2775 Value variant =
2776 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2777 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2778
2779 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2780 std::get<std::string>(variant)))
2781 {
2782 case nmi::NMISource::BMCSourceSignal::None:
2783 bmcSource = static_cast<uint8_t>(NmiSource::none);
2784 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002785 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2786 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002787 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002788 case nmi::NMISource::BMCSourceSignal::Watchdog:
2789 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002790 break;
2791 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2792 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2793 break;
2794 case nmi::NMISource::BMCSourceSignal::MemoryError:
2795 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2796 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002797 case nmi::NMISource::BMCSourceSignal::PciBusError:
2798 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002799 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002800 case nmi::NMISource::BMCSourceSignal::PCH:
2801 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002802 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002803 case nmi::NMISource::BMCSourceSignal::Chipset:
2804 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002805 break;
2806 default:
2807 phosphor::logging::log<phosphor::logging::level::ERR>(
2808 "NMI source: invalid property!",
2809 phosphor::logging::entry(
2810 "PROP=%s", std::get<std::string>(variant).c_str()));
2811 return ipmi::responseResponseError();
2812 }
2813 }
2814 catch (sdbusplus::exception::SdBusError& e)
2815 {
2816 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2817 return ipmi::responseResponseError();
2818 }
2819
2820 return ipmi::responseSuccess(bmcSource);
2821}
2822
2823ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2824{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002825 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002826
2827 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2828 nmi::NMISource::BMCSourceSignal::None;
2829
2830 switch (NmiSource(sourceId))
2831 {
2832 case NmiSource::none:
2833 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2834 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002835 case NmiSource::frontPanelButton:
2836 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08002837 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002838 case NmiSource::watchdog:
2839 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08002840 break;
2841 case NmiSource::chassisCmd:
2842 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2843 break;
2844 case NmiSource::memoryError:
2845 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2846 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002847 case NmiSource::pciBusError:
2848 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08002849 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002850 case NmiSource::pch:
2851 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08002852 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002853 case NmiSource::chipset:
2854 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08002855 break;
2856 default:
2857 phosphor::logging::log<phosphor::logging::level::ERR>(
2858 "NMI source: invalid property!");
2859 return ipmi::responseResponseError();
2860 }
2861
2862 try
2863 {
2864 // keep NMI signal source
2865 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2866 std::string service =
2867 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08002868 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2869 oemNmiBmcSourceObjPathProp,
2870 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002871 // set Enabled property to inform NMI source handling
2872 // to trigger a NMI_OUT BSOD.
2873 // if it's triggered by NMI source property changed,
2874 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2875 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2876 {
2877 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2878 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2879 static_cast<bool>(true));
2880 }
Chen Yugang39736d52019-07-12 16:24:33 +08002881 }
2882 catch (sdbusplus::exception_t& e)
2883 {
2884 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2885 return ipmi::responseResponseError();
2886 }
2887
2888 return ipmi::responseSuccess();
2889}
2890
James Feist63efafa2019-07-24 12:39:21 -07002891namespace dimmOffset
2892{
2893constexpr const char* dimmPower = "DimmPower";
2894constexpr const char* staticCltt = "StaticCltt";
2895constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2896constexpr const char* offsetInterface =
2897 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2898constexpr const char* property = "DimmOffset";
2899
2900}; // namespace dimmOffset
2901
2902ipmi::RspType<>
2903 ipmiOEMSetDimmOffset(uint8_t type,
2904 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2905{
2906 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2907 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2908 {
2909 return ipmi::responseInvalidFieldRequest();
2910 }
2911
2912 if (data.empty())
2913 {
2914 return ipmi::responseInvalidFieldRequest();
2915 }
2916 nlohmann::json json;
2917
2918 std::ifstream jsonStream(dimmOffsetFile);
2919 if (jsonStream.good())
2920 {
2921 json = nlohmann::json::parse(jsonStream, nullptr, false);
2922 if (json.is_discarded())
2923 {
2924 json = nlohmann::json();
2925 }
2926 jsonStream.close();
2927 }
2928
2929 std::string typeName;
2930 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2931 {
2932 typeName = dimmOffset::dimmPower;
2933 }
2934 else
2935 {
2936 typeName = dimmOffset::staticCltt;
2937 }
2938
2939 nlohmann::json& field = json[typeName];
2940
2941 for (const auto& [index, value] : data)
2942 {
2943 field[index] = value;
2944 }
2945
2946 for (nlohmann::json& val : field)
2947 {
2948 if (val == nullptr)
2949 {
2950 val = static_cast<uint8_t>(0);
2951 }
2952 }
2953
2954 std::ofstream output(dimmOffsetFile);
2955 if (!output.good())
2956 {
2957 std::cerr << "Error writing json file\n";
2958 return ipmi::responseResponseError();
2959 }
2960
2961 output << json.dump(4);
2962
2963 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2964 {
2965 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
2966
2967 std::variant<std::vector<uint8_t>> offsets =
2968 field.get<std::vector<uint8_t>>();
2969 auto call = bus->new_method_call(
2970 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
2971 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
2972 try
2973 {
2974 bus->call(call);
2975 }
2976 catch (sdbusplus::exception_t& e)
2977 {
2978 phosphor::logging::log<phosphor::logging::level::ERR>(
2979 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
2980 phosphor::logging::entry("ERR=%s", e.what()));
2981 return ipmi::responseResponseError();
2982 }
2983 }
2984
2985 return ipmi::responseSuccess();
2986}
2987
2988ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
2989{
2990
2991 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2992 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2993 {
2994 return ipmi::responseInvalidFieldRequest();
2995 }
2996
2997 std::ifstream jsonStream(dimmOffsetFile);
2998
2999 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3000 if (json.is_discarded())
3001 {
3002 std::cerr << "File error in " << dimmOffsetFile << "\n";
3003 return ipmi::responseResponseError();
3004 }
3005
3006 std::string typeName;
3007 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3008 {
3009 typeName = dimmOffset::dimmPower;
3010 }
3011 else
3012 {
3013 typeName = dimmOffset::staticCltt;
3014 }
3015
3016 auto it = json.find(typeName);
3017 if (it == json.end())
3018 {
3019 return ipmi::responseInvalidFieldRequest();
3020 }
3021
3022 if (it->size() <= index)
3023 {
3024 return ipmi::responseInvalidFieldRequest();
3025 }
3026
3027 uint8_t resp = it->at(index).get<uint8_t>();
3028 return ipmi::responseSuccess(resp);
3029}
3030
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003031namespace boot_options
3032{
3033
3034using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3035using IpmiValue = uint8_t;
3036constexpr auto ipmiDefault = 0;
3037
3038std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3039 {0x01, Source::Sources::Network},
3040 {0x02, Source::Sources::Disk},
3041 {0x05, Source::Sources::ExternalMedia},
3042 {0x0f, Source::Sources::RemovableMedia},
3043 {ipmiDefault, Source::Sources::Default}};
3044
3045std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003046 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003047
3048std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3049 {Source::Sources::Network, 0x01},
3050 {Source::Sources::Disk, 0x02},
3051 {Source::Sources::ExternalMedia, 0x05},
3052 {Source::Sources::RemovableMedia, 0x0f},
3053 {Source::Sources::Default, ipmiDefault}};
3054
3055std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003056 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003057
3058static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3059static constexpr auto bootSourceIntf =
3060 "xyz.openbmc_project.Control.Boot.Source";
3061static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3062static constexpr auto persistentObjPath =
3063 "/xyz/openbmc_project/control/host0/boot";
3064static constexpr auto oneTimePath =
3065 "/xyz/openbmc_project/control/host0/boot/one_time";
3066static constexpr auto bootSourceProp = "BootSource";
3067static constexpr auto bootModeProp = "BootMode";
3068static constexpr auto oneTimeBootEnableProp = "Enabled";
3069static constexpr auto httpBootMode =
3070 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3071
3072enum class BootOptionParameter : size_t
3073{
3074 setInProgress = 0x0,
3075 bootFlags = 0x5,
3076};
3077static constexpr uint8_t setComplete = 0x0;
3078static constexpr uint8_t setInProgress = 0x1;
3079static uint8_t transferStatus = setComplete;
3080static constexpr uint8_t setParmVersion = 0x01;
3081static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3082static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3083static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3084static constexpr uint8_t httpBoot = 0xd;
3085static constexpr uint8_t bootSourceMask = 0x3c;
3086
3087} // namespace boot_options
3088
3089ipmi::RspType<uint8_t, // version
3090 uint8_t, // param
3091 uint8_t, // data0, dependent on parameter
3092 std::optional<uint8_t> // data1, dependent on parameter
3093 >
3094 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3095{
3096 using namespace boot_options;
3097 uint8_t bootOption = 0;
3098
3099 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3100 {
3101 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3102 std::nullopt);
3103 }
3104
3105 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3106 {
3107 phosphor::logging::log<phosphor::logging::level::ERR>(
3108 "Unsupported parameter");
3109 return ipmi::responseResponseError();
3110 }
3111
3112 try
3113 {
3114 auto oneTimeEnabled = false;
3115 // read one time Enabled property
3116 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3117 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3118 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3119 enabledIntf, oneTimeBootEnableProp);
3120 oneTimeEnabled = std::get<bool>(variant);
3121
3122 // get BootSource and BootMode properties
3123 // according to oneTimeEnable
3124 auto bootObjPath = oneTimePath;
3125 if (oneTimeEnabled == false)
3126 {
3127 bootObjPath = persistentObjPath;
3128 }
3129
3130 service = getService(*dbus, bootModeIntf, bootObjPath);
3131 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3132 bootModeProp);
3133
3134 auto bootMode =
3135 Mode::convertModesFromString(std::get<std::string>(variant));
3136
3137 service = getService(*dbus, bootSourceIntf, bootObjPath);
3138 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3139 bootSourceProp);
3140
3141 if (std::get<std::string>(variant) == httpBootMode)
3142 {
3143 bootOption = httpBoot;
3144 }
3145 else
3146 {
3147 auto bootSource = Source::convertSourcesFromString(
3148 std::get<std::string>(variant));
3149 bootOption = sourceDbusToIpmi.at(bootSource);
3150 if (Source::Sources::Default == bootSource)
3151 {
3152 bootOption = modeDbusToIpmi.at(bootMode);
3153 }
3154 }
3155
3156 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3157 : setParmBootFlagsValidPermanent;
3158 bootOption <<= 2; // shift for responseconstexpr
3159 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3160 bootOption);
3161 }
3162 catch (sdbusplus::exception_t& e)
3163 {
3164 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3165 return ipmi::responseResponseError();
3166 }
3167}
3168
3169ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3170 std::optional<uint8_t> bootOption)
3171{
3172 using namespace boot_options;
3173 auto oneTimeEnabled = false;
3174
3175 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3176 {
3177 if (bootOption)
3178 {
3179 return ipmi::responseReqDataLenInvalid();
3180 }
3181
3182 if (transferStatus == setInProgress)
3183 {
3184 phosphor::logging::log<phosphor::logging::level::ERR>(
3185 "boot option set in progress!");
3186 return ipmi::responseResponseError();
3187 }
3188
3189 transferStatus = bootParam;
3190 return ipmi::responseSuccess();
3191 }
3192
3193 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3194 {
3195 phosphor::logging::log<phosphor::logging::level::ERR>(
3196 "Unsupported parameter");
3197 return ipmi::responseResponseError();
3198 }
3199
3200 if (!bootOption)
3201 {
3202 return ipmi::responseReqDataLenInvalid();
3203 }
3204
3205 if (((bootOption.value() & bootSourceMask) >> 2) !=
3206 httpBoot) // not http boot, exit
3207 {
3208 phosphor::logging::log<phosphor::logging::level::ERR>(
3209 "wrong boot option parameter!");
3210 return ipmi::responseParmOutOfRange();
3211 }
3212
3213 try
3214 {
3215 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3216 setParmBootFlagsPermanent;
3217
3218 // read one time Enabled property
3219 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3220 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3221 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3222 enabledIntf, oneTimeBootEnableProp);
3223 oneTimeEnabled = std::get<bool>(variant);
3224
3225 /*
3226 * Check if the current boot setting is onetime or permanent, if the
3227 * request in the command is otherwise, then set the "Enabled"
3228 * property in one_time object path to 'True' to indicate onetime
3229 * and 'False' to indicate permanent.
3230 *
3231 * Once the onetime/permanent setting is applied, then the bootMode
3232 * and bootSource is updated for the corresponding object.
3233 */
3234 if (permanent == oneTimeEnabled)
3235 {
3236 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3237 oneTimeBootEnableProp, !permanent);
3238 }
3239
3240 // set BootSource and BootMode properties
3241 // according to oneTimeEnable or persistent
3242 auto bootObjPath = oneTimePath;
3243 if (oneTimeEnabled == false)
3244 {
3245 bootObjPath = persistentObjPath;
3246 }
3247 std::string bootMode =
3248 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3249 std::string bootSource = httpBootMode;
3250
3251 service = getService(*dbus, bootModeIntf, bootObjPath);
3252 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3253 bootMode);
3254
3255 service = getService(*dbus, bootSourceIntf, bootObjPath);
3256 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3257 bootSourceProp, bootSource);
3258 }
3259 catch (sdbusplus::exception_t& e)
3260 {
3261 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3262 return ipmi::responseResponseError();
3263 }
3264
3265 return ipmi::responseSuccess();
3266}
3267
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003268using BasicVariantType =
3269 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3270 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3271 uint16_t, uint8_t, bool>;
3272using PropertyMapType =
3273 boost::container::flat_map<std::string, BasicVariantType>;
3274static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3275 "xyz.openbmc_project.Configuration.PSUPresence"};
3276int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3277 std::vector<uint64_t>& addrTable)
3278{
3279 boost::system::error_code ec;
3280 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3281 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3282 "/xyz/openbmc_project/object_mapper",
3283 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3284 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3285 if (ec)
3286 {
3287 phosphor::logging::log<phosphor::logging::level::ERR>(
3288 "Failed to set dbus property to cold redundancy");
3289 return -1;
3290 }
3291 for (const auto& object : subtree)
3292 {
3293 std::string pathName = object.first;
3294 for (const auto& serviceIface : object.second)
3295 {
3296 std::string serviceName = serviceIface.first;
3297
3298 ec.clear();
3299 PropertyMapType propMap =
3300 ctx->bus->yield_method_call<PropertyMapType>(
3301 ctx->yield, ec, serviceName, pathName,
3302 "org.freedesktop.DBus.Properties", "GetAll",
3303 "xyz.openbmc_project.Configuration.PSUPresence");
3304 if (ec)
3305 {
3306 phosphor::logging::log<phosphor::logging::level::ERR>(
3307 "Failed to set dbus property to cold redundancy");
3308 return -1;
3309 }
3310 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3311 auto psuAddress =
3312 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3313
3314 if (psuBus == nullptr || psuAddress == nullptr)
3315 {
3316 std::cerr << "error finding necessary "
3317 "entry in configuration\n";
3318 return -1;
3319 }
3320 bus = static_cast<uint8_t>(*psuBus);
3321 addrTable = *psuAddress;
3322 return 0;
3323 }
3324 }
3325 return -1;
3326}
3327
3328static const constexpr uint8_t addrOffset = 8;
3329static const constexpr uint8_t psuRevision = 0xd9;
3330static const constexpr uint8_t defaultPSUBus = 7;
3331// Second Minor, Primary Minor, Major
3332static const constexpr size_t verLen = 3;
3333ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3334{
3335 uint8_t bus = defaultPSUBus;
3336 std::vector<uint64_t> addrTable;
3337 std::vector<uint8_t> result;
3338 if (getPSUAddress(ctx, bus, addrTable))
3339 {
3340 std::cerr << "Failed to get PSU bus and address\n";
3341 return ipmi::responseResponseError();
3342 }
3343
3344 for (const auto& slaveAddr : addrTable)
3345 {
3346 std::vector<uint8_t> writeData = {psuRevision};
3347 std::vector<uint8_t> readBuf(verLen);
3348 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3349 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3350
3351 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3352 if (retI2C != ipmi::ccSuccess)
3353 {
3354 for (size_t idx = 0; idx < verLen; idx++)
3355 {
3356 result.emplace_back(0x00);
3357 }
3358 }
3359 else
3360 {
3361 for (const uint8_t& data : readBuf)
3362 {
3363 result.emplace_back(data);
3364 }
3365 }
3366 }
3367
3368 return ipmi::responseSuccess(result);
3369}
3370
Jason M. Bills64796042018-10-03 16:51:55 -07003371static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003372{
3373 phosphor::logging::log<phosphor::logging::level::INFO>(
3374 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003375 ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003376 ipmiOEMWildcard,
3377 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003378
3379 ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003380 ipmiOEMWildcard,
3381 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003382
3383 ipmiPrintAndRegister(intel::netFnGeneral,
3384 intel::general::cmdGetChassisIdentifier, NULL,
3385 ipmiOEMGetChassisIdentifier,
3386 PRIVILEGE_USER); // get chassis identifier
3387
3388 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3389 NULL, ipmiOEMSetSystemGUID,
3390 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003391
3392 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003393 registerHandler(prioOemBase, intel::netFnGeneral,
3394 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3395 ipmiOEMDisableBMCSystemReset);
3396
Jason M. Billsb02bf092019-08-15 13:01:56 -07003397 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003398 registerHandler(prioOemBase, intel::netFnGeneral,
3399 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3400 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003401
Vernon Mauery98bbf692019-09-16 11:14:59 -07003402 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3403 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003404
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003405 registerHandler(prioOemBase, intel::netFnGeneral,
3406 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3407 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003408
Vernon Mauery98bbf692019-09-16 11:14:59 -07003409 ipmiPrintAndRegister(intel::netFnGeneral,
3410 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3411 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303412
Vernon Mauery98bbf692019-09-16 11:14:59 -07003413 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3414 intel::general::cmdSendEmbeddedFWUpdStatus,
3415 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303416
Vernon Mauery98bbf692019-09-16 11:14:59 -07003417 ipmiPrintAndRegister(intel::netFnGeneral,
3418 intel::general::cmdSetPowerRestoreDelay, NULL,
3419 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3420
3421 ipmiPrintAndRegister(intel::netFnGeneral,
3422 intel::general::cmdGetPowerRestoreDelay, NULL,
3423 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3424
3425 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3426 intel::general::cmdSetOEMUser2Activation,
3427 Privilege::Callback, ipmiOEMSetUser2Activation);
3428
3429 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3430 intel::general::cmdSetSpecialUserPassword,
3431 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303432
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003433 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003434 registerHandler(prioOemBase, intel::netFnGeneral,
3435 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3436 ipmiOEMGetProcessorErrConfig);
3437
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003438 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003439 registerHandler(prioOemBase, intel::netFnGeneral,
3440 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3441 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003442
Vernon Mauery98bbf692019-09-16 11:14:59 -07003443 ipmiPrintAndRegister(intel::netFnGeneral,
3444 intel::general::cmdSetShutdownPolicy, NULL,
3445 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003446
Vernon Mauery98bbf692019-09-16 11:14:59 -07003447 ipmiPrintAndRegister(intel::netFnGeneral,
3448 intel::general::cmdGetShutdownPolicy, NULL,
3449 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003450
anil kumar appanaf945eee2019-09-25 23:29:11 +00003451 registerHandler(prioOemBase, intel::netFnGeneral,
3452 intel::general::cmdSetFanConfig, Privilege::User,
3453 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003454
Vernon Mauery98bbf692019-09-16 11:14:59 -07003455 registerHandler(prioOemBase, intel::netFnGeneral,
3456 intel::general::cmdGetFanConfig, Privilege::User,
3457 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003458
Vernon Mauery98bbf692019-09-16 11:14:59 -07003459 registerHandler(prioOemBase, intel::netFnGeneral,
3460 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3461 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003462
Vernon Mauery98bbf692019-09-16 11:14:59 -07003463 registerHandler(prioOemBase, intel::netFnGeneral,
3464 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3465 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003466
Vernon Mauery98bbf692019-09-16 11:14:59 -07003467 registerHandler(prioOemBase, intel::netFnGeneral,
3468 intel::general::cmdSetFscParameter, Privilege::User,
3469 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003470
Vernon Mauery98bbf692019-09-16 11:14:59 -07003471 registerHandler(prioOemBase, intel::netFnGeneral,
3472 intel::general::cmdGetFscParameter, Privilege::User,
3473 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303474
Vernon Mauery98bbf692019-09-16 11:14:59 -07003475 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3476 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3477 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003478
Vernon Mauery98bbf692019-09-16 11:14:59 -07003479 registerHandler(prioOemBase, intel::netFnGeneral,
3480 intel::general::cmdGetNmiStatus, Privilege::User,
3481 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003482
Vernon Mauery98bbf692019-09-16 11:14:59 -07003483 registerHandler(prioOemBase, intel::netFnGeneral,
3484 intel::general::cmdSetNmiStatus, Privilege::Operator,
3485 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003486
Vernon Mauery98bbf692019-09-16 11:14:59 -07003487 registerHandler(prioOemBase, intel::netFnGeneral,
3488 intel::general::cmdGetEfiBootOptions, Privilege::User,
3489 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003490
Vernon Mauery98bbf692019-09-16 11:14:59 -07003491 registerHandler(prioOemBase, intel::netFnGeneral,
3492 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3493 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303494
Vernon Mauery98bbf692019-09-16 11:14:59 -07003495 registerHandler(prioOemBase, intel::netFnGeneral,
3496 intel::general::cmdGetSecurityMode, Privilege::User,
3497 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303498
Vernon Mauery98bbf692019-09-16 11:14:59 -07003499 registerHandler(prioOemBase, intel::netFnGeneral,
3500 intel::general::cmdSetSecurityMode, Privilege::Admin,
3501 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003502
Vernon Mauery98bbf692019-09-16 11:14:59 -07003503 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3504 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003505
Vernon Mauery98bbf692019-09-16 11:14:59 -07003506 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3507 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3508 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3509
3510 registerHandler(prioOemBase, intel::netFnGeneral,
3511 intel::general::cmdSetFaultIndication, Privilege::Operator,
3512 ipmiOEMSetFaultIndication);
3513
3514 registerHandler(prioOemBase, intel::netFnGeneral,
3515 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3516 ipmiOEMSetCRConfig);
3517
3518 registerHandler(prioOemBase, intel::netFnGeneral,
3519 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3520 ipmiOEMGetCRConfig);
3521
3522 registerHandler(prioOemBase, intel::netFnGeneral,
3523 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003524 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003525
Vernon Mauery98bbf692019-09-16 11:14:59 -07003526 registerHandler(prioOemBase, intel::netFnGeneral,
3527 intel::general::cmdSetDimmOffset, Privilege::Operator,
3528 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003529
Vernon Mauery98bbf692019-09-16 11:14:59 -07003530 registerHandler(prioOemBase, intel::netFnGeneral,
3531 intel::general::cmdGetDimmOffset, Privilege::Operator,
3532 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003533
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003534 registerHandler(prioOemBase, intel::netFnGeneral,
3535 intel::general::cmdGetPSUVersion, Privilege::User,
3536 ipmiOEMGetPSUVersion);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003537}
3538
3539} // namespace ipmi