blob: 2697d007f92279266687c7bf54d7216ca18c680a [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>
Zhikui Rence4e73f2019-12-06 13:59:47 -080030#include <gpiod.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080031#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080032#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070033#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070034#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080036#include <phosphor-logging/log.hpp>
Chen Yugang7a04f3a2019-10-08 11:12:35 +080037#include <regex>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080038#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053039#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080040#include <string>
James Feist91244a62019-02-19 15:04:54 -080041#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080042#include <vector>
Chen Yugang97cf96e2019-11-01 08:55:11 +080043#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080044#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
45#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080046#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053047#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053048#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080049
50namespace ipmi
51{
Jason M. Bills64796042018-10-03 16:51:55 -070052static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070053
Jason M. Bills64796042018-10-03 16:51:55 -070054static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080055
Suryakanth Sekard509eb92018-11-15 17:44:11 +053056static constexpr auto ethernetIntf =
57 "xyz.openbmc_project.Network.EthernetInterface";
58static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
59static constexpr auto networkService = "xyz.openbmc_project.Network";
60static constexpr auto networkRoot = "/xyz/openbmc_project/network";
61
Chen Yugang97cf96e2019-11-01 08:55:11 +080062static constexpr const char* oemNmiSourceIntf =
63 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080064static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080065 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080066static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
67static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
68
James Feist63efafa2019-07-24 12:39:21 -070069static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
70
Chen Yugang39736d52019-07-12 16:24:33 +080071enum class NmiSource : uint8_t
72{
73 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080074 frontPanelButton = 1,
75 watchdog = 2,
76 chassisCmd = 3,
77 memoryError = 4,
78 pciBusError = 5,
79 pch = 6,
80 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080081};
82
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053083enum class SpecialUserIndex : uint8_t
84{
85 rootUser = 0,
86 atScaleDebugUser = 1
87};
88
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053089static constexpr const char* restricionModeService =
90 "xyz.openbmc_project.RestrictionMode.Manager";
91static constexpr const char* restricionModeBasePath =
92 "/xyz/openbmc_project/control/security/restriction_mode";
93static constexpr const char* restricionModeIntf =
94 "xyz.openbmc_project.Control.Security.RestrictionMode";
95static constexpr const char* restricionModeProperty = "RestrictionMode";
96
97static constexpr const char* specialModeService =
98 "xyz.openbmc_project.SpecialMode";
99static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530100 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530101static constexpr const char* specialModeIntf =
102 "xyz.openbmc_project.Security.SpecialMode";
103static constexpr const char* specialModeProperty = "SpecialMode";
104
105static constexpr const char* dBusPropertyIntf =
106 "org.freedesktop.DBus.Properties";
107static constexpr const char* dBusPropertyGetMethod = "Get";
108static constexpr const char* dBusPropertySetMethod = "Set";
109
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800110// return code: 0 successful
111int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
112{
113 std::string objpath = "/xyz/openbmc_project/FruDevice";
114 std::string intf = "xyz.openbmc_project.FruDeviceManager";
115 std::string service = getService(bus, intf, objpath);
116 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
117 if (valueTree.empty())
118 {
119 phosphor::logging::log<phosphor::logging::level::ERR>(
120 "No object implements interface",
121 phosphor::logging::entry("INTF=%s", intf.c_str()));
122 return -1;
123 }
124
Jason M. Bills64796042018-10-03 16:51:55 -0700125 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800126 {
127 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
128 if (interface == item.second.end())
129 {
130 continue;
131 }
132
133 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
134 if (property == interface->second.end())
135 {
136 continue;
137 }
138
139 try
140 {
141 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700142 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700143 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800144 {
145 phosphor::logging::log<phosphor::logging::level::ERR>(
146 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800147 return -1;
148 }
Jason M. Bills64796042018-10-03 16:51:55 -0700149 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800150 return 0;
151 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700152 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800153 {
Jason M. Bills64796042018-10-03 16:51:55 -0700154 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800155 return -1;
156 }
157 }
158 return -1;
159}
Jason M. Bills64796042018-10-03 16:51:55 -0700160
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800161ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
162 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700163 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800164{
Jason M. Bills64796042018-10-03 16:51:55 -0700165 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800166 // Status code.
167 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700168 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800169 return rc;
170}
171
172// Returns the Chassis Identifier (serial #)
173ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
174 ipmi_request_t request,
175 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700176 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 ipmi_context_t context)
178{
179 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700180 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800181 {
Jason M. Bills64796042018-10-03 16:51:55 -0700182 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 return IPMI_CC_REQ_DATA_LEN_INVALID;
184 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700185 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
186 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800187 {
Jason M. Bills64796042018-10-03 16:51:55 -0700188 *dataLen = serial.size(); // length will never exceed response length
189 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800190 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700191 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192 return IPMI_CC_OK;
193 }
Jason M. Bills64796042018-10-03 16:51:55 -0700194 *dataLen = 0;
195 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800196}
197
198ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
199 ipmi_request_t request,
200 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700201 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800202{
203 static constexpr size_t safeBufferLength = 50;
204 char buf[safeBufferLength] = {0};
205 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
206
Jason M. Bills64796042018-10-03 16:51:55 -0700207 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800208 {
Jason M. Bills64796042018-10-03 16:51:55 -0700209 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800210 return IPMI_CC_REQ_DATA_LEN_INVALID;
211 }
212
Jason M. Bills64796042018-10-03 16:51:55 -0700213 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800214
215 snprintf(
216 buf, safeBufferLength,
217 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
218 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
219 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
220 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
221 Data->node3, Data->node2, Data->node1);
222 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
223 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800224
225 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
226 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700227 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
228 std::string service = getService(*dbus, intf, objpath);
229 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800230 return IPMI_CC_OK;
231}
232
Jason M. Billsb02bf092019-08-15 13:01:56 -0700233ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
234 uint7_t reserved1)
235{
236 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
237
238 try
239 {
240 auto service =
241 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
242 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
243 bmcResetDisablesIntf, "ResetOnSMI",
244 !disableResetOnSMI);
245 }
246 catch (std::exception& e)
247 {
248 phosphor::logging::log<phosphor::logging::level::ERR>(
249 "Failed to set BMC reset disables",
250 phosphor::logging::entry("EXCEPTION=%s", e.what()));
251 return ipmi::responseUnspecifiedError();
252 }
253
254 return ipmi::responseSuccess();
255}
256
257ipmi::RspType<bool, // disableResetOnSMI
258 uint7_t // reserved
259 >
260 ipmiOEMGetBMCResetDisables()
261{
262 bool disableResetOnSMI = true;
263
264 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
265 try
266 {
267 auto service =
268 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
269 Value variant =
270 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
271 bmcResetDisablesIntf, "ResetOnSMI");
272 disableResetOnSMI = !std::get<bool>(variant);
273 }
274 catch (std::exception& e)
275 {
276 phosphor::logging::log<phosphor::logging::level::ERR>(
277 "Failed to get BMC reset disables",
278 phosphor::logging::entry("EXCEPTION=%s", e.what()));
279 return ipmi::responseUnspecifiedError();
280 }
281
282 return ipmi::responseSuccess(disableResetOnSMI, 0);
283}
284
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800285ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
286 ipmi_request_t request, ipmi_response_t response,
287 ipmi_data_len_t dataLen, ipmi_context_t context)
288{
289 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
290
Jason M. Bills64796042018-10-03 16:51:55 -0700291 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800292 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 *dataLen = 0;
294 return IPMI_CC_REQ_DATA_LEN_INVALID;
295 }
Jason M. Bills64796042018-10-03 16:51:55 -0700296 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297
Vernon Mauery15419dd2019-05-24 09:40:30 -0700298 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
299 std::string service = getService(*dbus, biosIntf, biosObjPath);
300 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800301 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
302 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700303 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800304 *dataLen = 1;
305 return IPMI_CC_OK;
306}
307
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800308bool getSwVerInfo(uint8_t& bmcMajor, uint8_t& bmcMinor, uint8_t& meMajor,
309 uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800310{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800311 // step 1 : get BMC Major and Minor numbers from its DBUS property
312 std::optional<MetaRevision> rev{};
313 try
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800314 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800315 std::string version = getActiveSoftwareVersionInfo();
316 rev = convertIntelVersion(version);
317 }
318 catch (const std::exception& e)
319 {
320 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800321 }
322
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800323 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800324 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800325 MetaRevision revision = rev.value();
326 bmcMajor = revision.major;
327
328 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
329 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
330 }
331
332 // step 2 : get ME Major and Minor numbers from its DBUS property
333 try
334 {
335 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
336 std::string service =
337 getService(*dbus, "xyz.openbmc_project.Software.Version",
338 "/xyz/openbmc_project/me_version");
339 Value variant =
340 getDbusProperty(*dbus, service, "/xyz/openbmc_project/me_version",
341 "xyz.openbmc_project.Software.Version", "Version");
342
343 std::string& meString = std::get<std::string>(variant);
344
345 // get ME major number
346 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
347 constexpr size_t matchedPhosphor = 6;
348 std::smatch results;
349 if (std::regex_match(meString, results, pattern1))
350 {
351 if (results.size() == matchedPhosphor)
352 {
353 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
354 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
355 }
356 }
357 }
358 catch (sdbusplus::exception::SdBusError& e)
359 {
360 return false;
361 }
362 return true;
363}
364
365ipmi::RspType<
366 std::variant<std::string,
367 std::tuple<uint8_t, std::array<uint8_t, 2>,
368 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
369 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
370 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
371 ipmiOEMGetDeviceInfo(uint8_t entityType, uint8_t countToRead,
372 uint8_t offset)
373{
374 if (countToRead == 0)
375 {
376 return ipmi::responseReqDataLenInvalid();
377 }
378
379 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
380 {
381 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800382 }
383
384 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800385 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800386 {
387 case OEMDevEntityType::biosId:
388 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700389 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
390 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800391 try
392 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700393 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800394 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700395 std::string& idString = std::get<std::string>(variant);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800396 if (offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800397 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800398 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800399 }
Jason M. Bills64796042018-10-03 16:51:55 -0700400 size_t length = 0;
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800401 if (countToRead > (idString.size() - offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700402 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800403 length = idString.size() - offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700404 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800405 else
406 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800407 length = countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800408 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800409
410 std::string readBuf = {0};
411 readBuf.resize(length);
412 std::copy_n(idString.begin() + offset, length,
413 (readBuf.begin()));
414 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800415 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700416 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800417 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800418 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800419 }
420 }
421 break;
422
423 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800424 {
425 constexpr const size_t verLen = 2;
426 constexpr const size_t verTotalLen = 10;
427 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
428 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
429 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
430 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
431 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
432 // data0/1: BMC version number; data6/7: ME version number
433 // the others: HSC0/1/2 version number, not avaible.
434 if (true != getSwVerInfo(bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
435 {
436 return ipmi::responseUnspecifiedError();
437 }
438 return ipmi::responseSuccess(
439 std::tuple<
440 uint8_t, std::array<uint8_t, verLen>,
441 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
442 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
443 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
444 }
445 break;
446
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800447 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800448 {
449 constexpr const size_t sdrLen = 2;
450 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
451 return ipmi::responseSuccess(
452 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
453 readBuf});
454 }
455 break;
456
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800457 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800458 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800459 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800460}
461
462ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
463 ipmi_request_t request, ipmi_response_t response,
464 ipmi_data_len_t dataLen, ipmi_context_t context)
465{
466 if (*dataLen != 0)
467 {
Jason M. Bills64796042018-10-03 16:51:55 -0700468 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800469 return IPMI_CC_REQ_DATA_LEN_INVALID;
470 }
471
472 *dataLen = 1;
473 uint8_t* res = reinterpret_cast<uint8_t*>(response);
474 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
475 // AIC is available so that BIOS will not timeout repeatly which leads to
476 // slow booting.
477 *res = 0; // Byte1=Count of SlotPosition/FruID records.
478 return IPMI_CC_OK;
479}
480
Jason M. Bills64796042018-10-03 16:51:55 -0700481ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
482 ipmi_request_t request,
483 ipmi_response_t response,
484 ipmi_data_len_t dataLen,
485 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800486{
Jason M. Bills64796042018-10-03 16:51:55 -0700487 GetPowerRestoreDelayRes* resp =
488 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
489
490 if (*dataLen != 0)
491 {
492 *dataLen = 0;
493 return IPMI_CC_REQ_DATA_LEN_INVALID;
494 }
495
Vernon Mauery15419dd2019-05-24 09:40:30 -0700496 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700497 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700498 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700499 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700500 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700501 powerRestoreDelayIntf, powerRestoreDelayProp);
502
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700503 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700504 resp->byteLSB = delay;
505 resp->byteMSB = delay >> 8;
506
507 *dataLen = sizeof(GetPowerRestoreDelayRes);
508
509 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800510}
511
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800512static uint8_t bcdToDec(uint8_t val)
513{
514 return ((val / 16 * 10) + (val % 16));
515}
516
517// Allows an update utility or system BIOS to send the status of an embedded
518// firmware update attempt to the BMC. After received, BMC will create a logging
519// record.
520ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
521 uint8_t majorRevision,
522 uint8_t minorRevision,
523 uint32_t auxInfo)
524{
525 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700526 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800527 target = (target & selEvtTargetMask) >> selEvtTargetShift;
528
529 /* make sure the status is 0, 1, or 2 as per the spec */
530 if (status > 2)
531 {
532 return ipmi::response(ipmi::ccInvalidFieldRequest);
533 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700534 /* make sure the target is 0, 1, 2, or 4 as per the spec */
535 if (target > 4 || target == 3)
536 {
537 return ipmi::response(ipmi::ccInvalidFieldRequest);
538 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800539 /*orignal OEM command is to record OEM SEL.
540 But openbmc does not support OEM SEL, so we redirect it to redfish event
541 logging. */
542 std::string buildInfo;
543 std::string action;
544 switch (FWUpdateTarget(target))
545 {
546 case FWUpdateTarget::targetBMC:
547 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700548 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800549 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
550 " BuildID: " + std::to_string(auxInfo);
551 buildInfo += std::to_string(auxInfo);
552 break;
553 case FWUpdateTarget::targetBIOS:
554 firmware = "BIOS";
555 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700556 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800557 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
558 " minor: " +
559 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
560 " ReleaseNumber: " + // ASCII encoded
561 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
562 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
563 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
564 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
565 break;
566 case FWUpdateTarget::targetME:
567 firmware = "ME";
568 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700569 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800570 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
571 " minor2: " +
572 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
573 " build1: " +
574 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
575 " build2: " +
576 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
577 break;
578 case FWUpdateTarget::targetOEMEWS:
579 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700580 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800581 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
582 " BuildID: " + std::to_string(auxInfo);
583 break;
584 }
585
Jason M. Billsdc249272019-04-03 09:58:40 -0700586 static const std::string openBMCMessageRegistryVersion("0.1");
587 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
588
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800589 switch (status)
590 {
591 case 0x0:
592 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700593 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800594 break;
595 case 0x1:
596 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700597 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800598 break;
599 case 0x2:
600 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700601 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800602 break;
603 default:
604 action = "unknown";
605 break;
606 }
607
Jason M. Billsdc249272019-04-03 09:58:40 -0700608 std::string firmwareInstanceStr =
609 firmware + " instance: " + std::to_string(instance);
610 std::string message("[firmware update] " + firmwareInstanceStr +
611 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800612
613 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700614 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
615 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
616 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800617 return ipmi::responseSuccess();
618}
619
Jason M. Bills64796042018-10-03 16:51:55 -0700620ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
621 ipmi_request_t request,
622 ipmi_response_t response,
623 ipmi_data_len_t dataLen,
624 ipmi_context_t context)
625{
626 SetPowerRestoreDelayReq* data =
627 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
628 uint16_t delay = 0;
629
630 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
631 {
632 *dataLen = 0;
633 return IPMI_CC_REQ_DATA_LEN_INVALID;
634 }
635 delay = data->byteMSB;
636 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700637 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700638 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700639 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
640 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700641 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
642 *dataLen = 0;
643
644 return IPMI_CC_OK;
645}
646
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700647static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700648{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700649 static constexpr const char* cpuPresencePathPrefix =
650 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
651 static constexpr const char* cpuPresenceIntf =
652 "xyz.openbmc_project.Inventory.Item";
653 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
654 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
655 try
Jason M. Bills64796042018-10-03 16:51:55 -0700656 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700657 auto service =
658 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
659
660 ipmi::Value result = ipmi::getDbusProperty(
661 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
662 return std::get<bool>(result);
663 }
664 catch (const std::exception& e)
665 {
666 phosphor::logging::log<phosphor::logging::level::INFO>(
667 "Cannot find processor presence",
668 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
669 return false;
670 }
671}
672
673ipmi::RspType<bool, // CATERR Reset Enabled
674 bool, // ERR2 Reset Enabled
675 uint6_t, // reserved
676 uint8_t, // reserved, returns 0x3F
677 uint6_t, // CPU1 CATERR Count
678 uint2_t, // CPU1 Status
679 uint6_t, // CPU2 CATERR Count
680 uint2_t, // CPU2 Status
681 uint6_t, // CPU3 CATERR Count
682 uint2_t, // CPU3 Status
683 uint6_t, // CPU4 CATERR Count
684 uint2_t, // CPU4 Status
685 uint8_t // Crashdump Count
686 >
687 ipmiOEMGetProcessorErrConfig()
688{
689 bool resetOnCATERR = false;
690 bool resetOnERR2 = false;
691 uint6_t cpu1CATERRCount = 0;
692 uint6_t cpu2CATERRCount = 0;
693 uint6_t cpu3CATERRCount = 0;
694 uint6_t cpu4CATERRCount = 0;
695 uint8_t crashdumpCount = 0;
696 uint2_t cpu1Status =
697 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
698 uint2_t cpu2Status =
699 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
700 uint2_t cpu3Status =
701 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
702 uint2_t cpu4Status =
703 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
704
705 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
706 try
707 {
708 auto service = ipmi::getService(*busp, processorErrConfigIntf,
709 processorErrConfigObjPath);
710
711 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
712 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
713 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
714 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
715 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
716 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
717 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
718 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
719 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
720 }
721 catch (const std::exception& e)
722 {
723 phosphor::logging::log<phosphor::logging::level::ERR>(
724 "Failed to fetch processor error config",
725 phosphor::logging::entry("ERROR=%s", e.what()));
726 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700727 }
728
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700729 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
730 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
731 cpu2Status, cpu3CATERRCount, cpu3Status,
732 cpu4CATERRCount, cpu4Status, crashdumpCount);
733}
Jason M. Bills64796042018-10-03 16:51:55 -0700734
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700735ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
736 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
737 std::optional<bool> clearCPUErrorCount,
738 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
739{
740 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700741
742 try
743 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700744 auto service = ipmi::getService(*busp, processorErrConfigIntf,
745 processorErrConfigObjPath);
746 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
747 processorErrConfigIntf, "ResetOnCATERR",
748 resetOnCATERR);
749 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
750 processorErrConfigIntf, "ResetOnERR2",
751 resetOnERR2);
752 if (clearCPUErrorCount.value_or(false))
753 {
754 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700755 processorErrConfigIntf, "ErrorCountCPU1",
756 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700757 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700758 processorErrConfigIntf, "ErrorCountCPU2",
759 static_cast<uint8_t>(0));
760 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
761 processorErrConfigIntf, "ErrorCountCPU3",
762 static_cast<uint8_t>(0));
763 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
764 processorErrConfigIntf, "ErrorCountCPU4",
765 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700766 }
767 if (clearCrashdumpCount.value_or(false))
768 {
769 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700770 processorErrConfigIntf, "CrashdumpCount",
771 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700772 }
Jason M. Bills64796042018-10-03 16:51:55 -0700773 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700774 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700775 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800776 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700777 "Failed to set processor error config",
778 phosphor::logging::entry("EXCEPTION=%s", e.what()));
779 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700780 }
781
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700782 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700783}
784
Yong Li703922d2018-11-06 13:25:31 +0800785ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
786 ipmi_request_t request,
787 ipmi_response_t response,
788 ipmi_data_len_t dataLen,
789 ipmi_context_t context)
790{
791 GetOEMShutdownPolicyRes* resp =
792 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
793
794 if (*dataLen != 0)
795 {
796 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800797 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800798 *dataLen = 0;
799 return IPMI_CC_REQ_DATA_LEN_INVALID;
800 }
801
802 *dataLen = 0;
803
804 try
805 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700806 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800807 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700808 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
809 Value variant = getDbusProperty(
810 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
811 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800812
813 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
814 convertPolicyFromString(std::get<std::string>(variant)) ==
815 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
816 NoShutdownOnOCOT)
817 {
818 resp->policy = 0;
819 }
820 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
821 convertPolicyFromString(std::get<std::string>(variant)) ==
822 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
823 Policy::ShutdownOnOCOT)
824 {
825 resp->policy = 1;
826 }
827 else
828 {
829 phosphor::logging::log<phosphor::logging::level::ERR>(
830 "oem_set_shutdown_policy: invalid property!",
831 phosphor::logging::entry(
832 "PROP=%s", std::get<std::string>(variant).c_str()));
833 return IPMI_CC_UNSPECIFIED_ERROR;
834 }
Yong Li703922d2018-11-06 13:25:31 +0800835 // TODO needs to check if it is multi-node products,
836 // policy is only supported on node 3/4
837 resp->policySupport = shutdownPolicySupported;
838 }
839 catch (sdbusplus::exception_t& e)
840 {
841 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
842 return IPMI_CC_UNSPECIFIED_ERROR;
843 }
844
845 *dataLen = sizeof(GetOEMShutdownPolicyRes);
846 return IPMI_CC_OK;
847}
848
849ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
850 ipmi_request_t request,
851 ipmi_response_t response,
852 ipmi_data_len_t dataLen,
853 ipmi_context_t context)
854{
855 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800856 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
857 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
858 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800859
860 // TODO needs to check if it is multi-node products,
861 // policy is only supported on node 3/4
862 if (*dataLen != 1)
863 {
864 phosphor::logging::log<phosphor::logging::level::ERR>(
865 "oem_set_shutdown_policy: invalid input len!");
866 *dataLen = 0;
867 return IPMI_CC_REQ_DATA_LEN_INVALID;
868 }
869
870 *dataLen = 0;
871 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
872 {
873 phosphor::logging::log<phosphor::logging::level::ERR>(
874 "oem_set_shutdown_policy: invalid input!");
875 return IPMI_CC_INVALID_FIELD_REQUEST;
876 }
877
Yong Li0669d192019-05-06 14:01:46 +0800878 if (*req == noShutdownOnOCOT)
879 {
880 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
881 Policy::NoShutdownOnOCOT;
882 }
883 else
884 {
885 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
886 Policy::ShutdownOnOCOT;
887 }
888
Yong Li703922d2018-11-06 13:25:31 +0800889 try
890 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700891 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800892 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700893 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800894 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700895 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800896 oemShutdownPolicyObjPathProp,
897 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800898 }
899 catch (sdbusplus::exception_t& e)
900 {
901 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
902 return IPMI_CC_UNSPECIFIED_ERROR;
903 }
904
905 return IPMI_CC_OK;
906}
907
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530908/** @brief implementation for check the DHCP or not in IPv4
909 * @param[in] Channel - Channel number
910 * @returns true or false.
911 */
912static bool isDHCPEnabled(uint8_t Channel)
913{
914 try
915 {
916 auto ethdevice = getChannelName(Channel);
917 if (ethdevice.empty())
918 {
919 return false;
920 }
921 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700922 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530923 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700924 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
925 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530926 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700927 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530928 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
929 {
930 return true;
931 }
932 else
933 {
934 return false;
935 }
936 }
937 catch (sdbusplus::exception_t& e)
938 {
939 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
940 return true;
941 }
942}
943
944/** @brief implementes for check the DHCP or not in IPv6
945 * @param[in] Channel - Channel number
946 * @returns true or false.
947 */
948static bool isDHCPIPv6Enabled(uint8_t Channel)
949{
950
951 try
952 {
953 auto ethdevice = getChannelName(Channel);
954 if (ethdevice.empty())
955 {
956 return false;
957 }
958 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700959 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530960 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700961 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
962 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530963 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700964 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530965 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
966 {
967 return true;
968 }
969 else
970 {
971 return false;
972 }
973 }
974 catch (sdbusplus::exception_t& e)
975 {
976 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
977 return true;
978 }
979}
980
981/** @brief implementes the creating of default new user
982 * @param[in] userName - new username in 16 bytes.
983 * @param[in] userPassword - new password in 20 bytes
984 * @returns ipmi completion code.
985 */
986ipmi::RspType<> ipmiOEMSetUser2Activation(
987 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
988 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
989{
990 bool userState = false;
991 // Check for System Interface not exist and LAN should be static
992 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
993 {
994 ChannelInfo chInfo;
995 try
996 {
997 getChannelInfo(channel, chInfo);
998 }
999 catch (sdbusplus::exception_t& e)
1000 {
1001 phosphor::logging::log<phosphor::logging::level::ERR>(
1002 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1003 phosphor::logging::entry("MSG: %s", e.description()));
1004 return ipmi::response(ipmi::ccUnspecifiedError);
1005 }
1006 if (chInfo.mediumType ==
1007 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1008 {
1009 phosphor::logging::log<phosphor::logging::level::ERR>(
1010 "ipmiOEMSetUser2Activation: system interface exist .");
1011 return ipmi::response(ipmi::ccCommandNotAvailable);
1012 }
1013 else
1014 {
1015
1016 if (chInfo.mediumType ==
1017 static_cast<uint8_t>(EChannelMediumType::lan8032))
1018 {
1019 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1020 {
1021 phosphor::logging::log<phosphor::logging::level::ERR>(
1022 "ipmiOEMSetUser2Activation: DHCP enabled .");
1023 return ipmi::response(ipmi::ccCommandNotAvailable);
1024 }
1025 }
1026 }
1027 }
1028 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1029 if (ipmi::ccSuccess ==
1030 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1031 {
1032 if (enabledUsers > 1)
1033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(
1035 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1036 return ipmi::response(ipmi::ccCommandNotAvailable);
1037 }
1038 // Check the user 2 is enabled or not
1039 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1040 if (userState == true)
1041 {
1042 phosphor::logging::log<phosphor::logging::level::ERR>(
1043 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1044 return ipmi::response(ipmi::ccCommandNotAvailable);
1045 }
1046 }
1047 else
1048 {
1049 return ipmi::response(ipmi::ccUnspecifiedError);
1050 }
1051
1052#if BYTE_ORDER == LITTLE_ENDIAN
1053 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1054#endif
1055#if BYTE_ORDER == BIG_ENDIAN
1056 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1057#endif
1058
1059 if (ipmi::ccSuccess ==
1060 ipmiUserSetUserName(ipmiDefaultUserId,
1061 reinterpret_cast<const char*>(userName.data())))
1062 {
1063 if (ipmi::ccSuccess ==
1064 ipmiUserSetUserPassword(
1065 ipmiDefaultUserId,
1066 reinterpret_cast<const char*>(userPassword.data())))
1067 {
1068 if (ipmi::ccSuccess ==
1069 ipmiUserSetPrivilegeAccess(
1070 ipmiDefaultUserId,
1071 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1072 privAccess, true))
1073 {
1074 phosphor::logging::log<phosphor::logging::level::INFO>(
1075 "ipmiOEMSetUser2Activation: user created successfully ");
1076 return ipmi::responseSuccess();
1077 }
1078 }
1079 // we need to delete the default user id which added in this command as
1080 // password / priv setting is failed.
1081 ipmiUserSetUserName(ipmiDefaultUserId, "");
1082 phosphor::logging::log<phosphor::logging::level::ERR>(
1083 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1084 }
1085 else
1086 {
1087 phosphor::logging::log<phosphor::logging::level::ERR>(
1088 "ipmiOEMSetUser2Activation: Setting username failed.");
1089 }
1090
1091 return ipmi::response(ipmi::ccCommandNotAvailable);
1092}
1093
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301094/** @brief implementes executing the linux command
1095 * @param[in] linux command
1096 * @returns status
1097 */
1098
1099static uint8_t executeCmd(const char* path)
1100{
1101 boost::process::child execProg(path);
1102 execProg.wait();
1103
1104 int retCode = execProg.exit_code();
1105 if (retCode)
1106 {
1107 return ipmi::ccUnspecifiedError;
1108 }
1109 return ipmi::ccSuccess;
1110}
1111
1112/** @brief implementes ASD Security event logging
1113 * @param[in] Event message string
1114 * @param[in] Event Severity
1115 * @returns status
1116 */
1117
1118static void atScaleDebugEventlog(std::string msg, int severity)
1119{
1120 std::string eventStr = "OpenBMC.0.1." + msg;
1121 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1122 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1123 eventStr.c_str(), NULL);
1124}
1125
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301126/** @brief implementes setting password for special user
1127 * @param[in] specialUserIndex
1128 * @param[in] userPassword - new password in 20 bytes
1129 * @returns ipmi completion code.
1130 */
1131ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1132 uint8_t specialUserIndex,
1133 std::vector<uint8_t> userPassword)
1134{
1135 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301136 ipmi_ret_t status = ipmi::ccSuccess;
1137
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301138 try
1139 {
1140 getChannelInfo(ctx->channel, chInfo);
1141 }
1142 catch (sdbusplus::exception_t& e)
1143 {
1144 phosphor::logging::log<phosphor::logging::level::ERR>(
1145 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1146 phosphor::logging::entry("MSG: %s", e.description()));
1147 return ipmi::responseUnspecifiedError();
1148 }
1149 if (chInfo.mediumType !=
1150 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1151 {
1152 phosphor::logging::log<phosphor::logging::level::ERR>(
1153 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1154 "interface");
1155 return ipmi::responseCommandNotAvailable();
1156 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301157
1158 // 0 for root user and 1 for AtScaleDebug is allowed
1159 if (specialUserIndex >
1160 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301161 {
1162 phosphor::logging::log<phosphor::logging::level::ERR>(
1163 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1164 return ipmi::responseParmOutOfRange();
1165 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301166 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301167 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301168 constexpr uint8_t minPasswordSizeRequired = 6;
1169 std::string passwd;
1170 if (userPassword.size() < minPasswordSizeRequired ||
1171 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1172 {
1173 return ipmi::responseReqDataLenInvalid();
1174 }
1175 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1176 userPassword.size());
1177 if (specialUserIndex ==
1178 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1179 {
1180 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1181
1182 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1183 }
1184 else
1185 {
1186 status = ipmiSetSpecialUserPassword("root", passwd);
1187 }
1188 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301189 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301190 else
1191 {
1192 if (specialUserIndex ==
1193 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1194 {
1195 status = executeCmd("passwd -d root");
1196 }
1197 else
1198 {
1199
1200 status = executeCmd("passwd -d asdbg");
1201
1202 if (status == 0)
1203 {
1204 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1205 LOG_INFO);
1206 }
1207 }
1208 return ipmi::response(status);
1209 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301210}
1211
Kuiying Wang45f04982018-12-26 09:23:08 +08001212namespace ledAction
1213{
1214using namespace sdbusplus::xyz::openbmc_project::Led::server;
1215std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001216 {Physical::Action::Off, 0},
1217 {Physical::Action::On, 2},
1218 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001219
1220std::map<uint8_t, std::string> offsetObjPath = {
1221 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1222
1223} // namespace ledAction
1224
1225int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1226 const std::string& objPath, uint8_t& state)
1227{
1228 try
1229 {
1230 std::string service = getService(bus, intf, objPath);
1231 Value stateValue =
1232 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001233 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001234 state = ledAction::actionDbusToIpmi.at(
1235 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1236 convertActionFromString(strState));
1237 }
1238 catch (sdbusplus::exception::SdBusError& e)
1239 {
1240 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1241 return -1;
1242 }
1243 return 0;
1244}
1245
1246ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1247 ipmi_request_t request, ipmi_response_t response,
1248 ipmi_data_len_t dataLen, ipmi_context_t context)
1249{
1250 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1251 // LED Status
1252 //[1:0] = Reserved
1253 //[3:2] = Status(Amber)
1254 //[5:4] = Status(Green)
1255 //[7:6] = System Identify
1256 // Status definitions:
1257 // 00b = Off
1258 // 01b = Blink
1259 // 10b = On
1260 // 11b = invalid
1261 if (*dataLen != 0)
1262 {
1263 phosphor::logging::log<phosphor::logging::level::ERR>(
1264 "oem_get_led_status: invalid input len!");
1265 *dataLen = 0;
1266 return IPMI_CC_REQ_DATA_LEN_INVALID;
1267 }
1268
1269 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1270 *resp = 0;
1271 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001272 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001273 for (auto it = ledAction::offsetObjPath.begin();
1274 it != ledAction::offsetObjPath.end(); ++it)
1275 {
1276 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001277 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001278 {
1279 phosphor::logging::log<phosphor::logging::level::ERR>(
1280 "oem_get_led_status: fail to get ID LED status!");
1281 return IPMI_CC_UNSPECIFIED_ERROR;
1282 }
1283 *resp |= state << it->first;
1284 }
1285
1286 *dataLen = sizeof(*resp);
1287 return IPMI_CC_OK;
1288}
1289
Yong Li23737fe2019-02-19 08:49:55 +08001290ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1291 ipmi_request_t request,
1292 ipmi_response_t response,
1293 ipmi_data_len_t dataLen,
1294 ipmi_context_t context)
1295{
1296 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1297 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1298
1299 if (*dataLen == 0)
1300 {
1301 phosphor::logging::log<phosphor::logging::level::ERR>(
1302 "CfgHostSerial: invalid input len!",
1303 phosphor::logging::entry("LEN=%d", *dataLen));
1304 return IPMI_CC_REQ_DATA_LEN_INVALID;
1305 }
1306
1307 switch (req->command)
1308 {
1309 case getHostSerialCfgCmd:
1310 {
1311 if (*dataLen != 1)
1312 {
1313 phosphor::logging::log<phosphor::logging::level::ERR>(
1314 "CfgHostSerial: invalid input len!");
1315 *dataLen = 0;
1316 return IPMI_CC_REQ_DATA_LEN_INVALID;
1317 }
1318
1319 *dataLen = 0;
1320
1321 boost::process::ipstream is;
1322 std::vector<std::string> data;
1323 std::string line;
1324 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1325 boost::process::std_out > is);
1326
1327 while (c1.running() && std::getline(is, line) && !line.empty())
1328 {
1329 data.push_back(line);
1330 }
1331
1332 c1.wait();
1333 if (c1.exit_code())
1334 {
1335 phosphor::logging::log<phosphor::logging::level::ERR>(
1336 "CfgHostSerial:: error on execute",
1337 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1338 // Using the default value
1339 *resp = 0;
1340 }
1341 else
1342 {
1343 if (data.size() != 1)
1344 {
1345 phosphor::logging::log<phosphor::logging::level::ERR>(
1346 "CfgHostSerial:: error on read env");
1347 return IPMI_CC_UNSPECIFIED_ERROR;
1348 }
1349 try
1350 {
1351 unsigned long tmp = std::stoul(data[0]);
1352 if (tmp > std::numeric_limits<uint8_t>::max())
1353 {
1354 throw std::out_of_range("Out of range");
1355 }
1356 *resp = static_cast<uint8_t>(tmp);
1357 }
1358 catch (const std::invalid_argument& e)
1359 {
1360 phosphor::logging::log<phosphor::logging::level::ERR>(
1361 "invalid config ",
1362 phosphor::logging::entry("ERR=%s", e.what()));
1363 return IPMI_CC_UNSPECIFIED_ERROR;
1364 }
1365 catch (const std::out_of_range& e)
1366 {
1367 phosphor::logging::log<phosphor::logging::level::ERR>(
1368 "out_of_range config ",
1369 phosphor::logging::entry("ERR=%s", e.what()));
1370 return IPMI_CC_UNSPECIFIED_ERROR;
1371 }
1372 }
1373
1374 *dataLen = 1;
1375 break;
1376 }
1377 case setHostSerialCfgCmd:
1378 {
1379 if (*dataLen != sizeof(CfgHostSerialReq))
1380 {
1381 phosphor::logging::log<phosphor::logging::level::ERR>(
1382 "CfgHostSerial: invalid input len!");
1383 *dataLen = 0;
1384 return IPMI_CC_REQ_DATA_LEN_INVALID;
1385 }
1386
1387 *dataLen = 0;
1388
1389 if (req->parameter > HostSerialCfgParamMax)
1390 {
1391 phosphor::logging::log<phosphor::logging::level::ERR>(
1392 "CfgHostSerial: invalid input!");
1393 return IPMI_CC_INVALID_FIELD_REQUEST;
1394 }
1395
1396 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1397 std::to_string(req->parameter));
1398
1399 c1.wait();
1400 if (c1.exit_code())
1401 {
1402 phosphor::logging::log<phosphor::logging::level::ERR>(
1403 "CfgHostSerial:: error on execute",
1404 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1405 return IPMI_CC_UNSPECIFIED_ERROR;
1406 }
1407 break;
1408 }
1409 default:
1410 phosphor::logging::log<phosphor::logging::level::ERR>(
1411 "CfgHostSerial: invalid input!");
1412 *dataLen = 0;
1413 return IPMI_CC_INVALID_FIELD_REQUEST;
1414 }
1415
1416 return IPMI_CC_OK;
1417}
1418
James Feist91244a62019-02-19 15:04:54 -08001419constexpr const char* thermalModeInterface =
1420 "xyz.openbmc_project.Control.ThermalMode";
1421constexpr const char* thermalModePath =
1422 "/xyz/openbmc_project/control/thermal_mode";
1423
1424bool getFanProfileInterface(
1425 sdbusplus::bus::bus& bus,
1426 boost::container::flat_map<
1427 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1428{
1429 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1430 "GetAll");
1431 call.append(thermalModeInterface);
1432 try
1433 {
1434 auto data = bus.call(call);
1435 data.read(resp);
1436 }
1437 catch (sdbusplus::exception_t& e)
1438 {
1439 phosphor::logging::log<phosphor::logging::level::ERR>(
1440 "getFanProfileInterface: can't get thermal mode!",
1441 phosphor::logging::entry("ERR=%s", e.what()));
1442 return false;
1443 }
1444 return true;
1445}
1446
anil kumar appanaf945eee2019-09-25 23:29:11 +00001447/**@brief implements the OEM set fan config.
1448 * @param selectedFanProfile - fan profile to enable
1449 * @param reserved1
1450 * @param performanceMode - Performance/Acoustic mode
1451 * @param reserved2
1452 * @param setPerformanceMode - set Performance/Acoustic mode
1453 * @param setFanProfile - set fan profile
1454 *
1455 * @return IPMI completion code.
1456 **/
1457ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1458
1459 uint2_t reserved1, bool performanceMode,
1460 uint3_t reserved2, bool setPerformanceMode,
1461 bool setFanProfile)
James Feist91244a62019-02-19 15:04:54 -08001462{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001463 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001464 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001465 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001466 }
James Feist91244a62019-02-19 15:04:54 -08001467 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001468 boost::container::flat_map<
1469 std::string, std::variant<std::vector<std::string>, std::string>>
1470 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001471 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1472 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001473 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001474 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001475 }
1476
1477 std::vector<std::string>* supported =
1478 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1479 if (supported == nullptr)
1480 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001481 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001482 }
1483 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001484 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001485 {
James Feist91244a62019-02-19 15:04:54 -08001486 if (performanceMode)
1487 {
1488
1489 if (std::find(supported->begin(), supported->end(),
1490 "Performance") != supported->end())
1491 {
1492 mode = "Performance";
1493 }
1494 }
1495 else
1496 {
James Feist91244a62019-02-19 15:04:54 -08001497 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1498 supported->end())
1499 {
1500 mode = "Acoustic";
1501 }
1502 }
1503 if (mode.empty())
1504 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001505 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001506 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001507
1508 try
1509 {
1510 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1511 thermalModeInterface, "Current", mode);
1512 }
1513 catch (sdbusplus::exception_t& e)
1514 {
1515 phosphor::logging::log<phosphor::logging::level::ERR>(
1516 "ipmiOEMSetFanConfig: can't set thermal mode!",
1517 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1518 return ipmi::responseResponseError();
1519 }
James Feist91244a62019-02-19 15:04:54 -08001520 }
1521
anil kumar appanaf945eee2019-09-25 23:29:11 +00001522 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001523}
1524
James Feist5b693632019-07-09 09:06:09 -07001525ipmi::RspType<uint8_t, // profile support map
1526 uint8_t, // fan control profile enable
1527 uint8_t, // flags
1528 uint32_t // dimm presence bit map
1529 >
1530 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001531{
James Feist91244a62019-02-19 15:04:54 -08001532 boost::container::flat_map<
1533 std::string, std::variant<std::vector<std::string>, std::string>>
1534 profileData;
1535
Vernon Mauery15419dd2019-05-24 09:40:30 -07001536 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1537 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001538 {
James Feist5b693632019-07-09 09:06:09 -07001539 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001540 }
1541
1542 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1543
1544 if (current == nullptr)
1545 {
1546 phosphor::logging::log<phosphor::logging::level::ERR>(
1547 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001548 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001549 }
1550 bool performance = (*current == "Performance");
1551
James Feist5b693632019-07-09 09:06:09 -07001552 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001553 if (performance)
1554 {
James Feist5b693632019-07-09 09:06:09 -07001555 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001556 }
1557
James Feist5b693632019-07-09 09:06:09 -07001558 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001559}
James Feist5f957ca2019-03-14 15:33:55 -07001560constexpr const char* cfmLimitSettingPath =
1561 "/xyz/openbmc_project/control/cfm_limit";
1562constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001563constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001564constexpr const size_t legacyPCHSensorNumber = 0x22;
1565constexpr const char* exitAirPathName = "Exit_Air";
1566constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001567constexpr const char* pidConfigurationIface =
1568 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001569
James Feist09f6b602019-08-08 11:30:03 -07001570static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001571{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001572 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001573 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001574 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1575 "/xyz/openbmc_project/object_mapper",
1576 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001577
James Feistacc8a4e2019-04-02 14:23:57 -07001578 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001579 std::string path;
1580 GetSubTreeType resp;
1581 try
1582 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001583 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001584 reply.read(resp);
1585 }
1586 catch (sdbusplus::exception_t&)
1587 {
1588 phosphor::logging::log<phosphor::logging::level::ERR>(
1589 "ipmiOEMGetFscParameter: mapper error");
1590 };
James Feist09f6b602019-08-08 11:30:03 -07001591 auto config =
1592 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1593 return pair.first.find(name) != std::string::npos;
1594 });
James Feistfaa4f222019-03-21 16:21:55 -07001595 if (config != resp.end())
1596 {
1597 path = std::move(config->first);
1598 }
1599 return path;
1600}
James Feist5f957ca2019-03-14 15:33:55 -07001601
James Feistacc8a4e2019-04-02 14:23:57 -07001602// flat map to make alphabetical
1603static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1604{
1605 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001606 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001607 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001608 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1609 "/xyz/openbmc_project/object_mapper",
1610 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001611
1612 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1613 GetSubTreeType resp;
1614
1615 try
1616 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001617 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001618 reply.read(resp);
1619 }
1620 catch (sdbusplus::exception_t&)
1621 {
1622 phosphor::logging::log<phosphor::logging::level::ERR>(
1623 "getFanConfigPaths: mapper error");
1624 };
1625 for (const auto& [path, objects] : resp)
1626 {
1627 if (objects.empty())
1628 {
1629 continue; // should be impossible
1630 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001631
1632 try
1633 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001634 ret.emplace(path,
1635 getAllDbusProperties(*dbus, objects[0].first, path,
1636 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001637 }
1638 catch (sdbusplus::exception_t& e)
1639 {
1640 phosphor::logging::log<phosphor::logging::level::ERR>(
1641 "getPidConfigs: can't get DbusProperties!",
1642 phosphor::logging::entry("ERR=%s", e.what()));
1643 }
James Feistacc8a4e2019-04-02 14:23:57 -07001644 }
1645 return ret;
1646}
1647
1648ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1649{
1650 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1651 if (data.empty())
1652 {
1653 return ipmi::responseResponseError();
1654 }
1655 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1656 for (const auto& [_, pid] : data)
1657 {
1658 auto findClass = pid.find("Class");
1659 if (findClass == pid.end())
1660 {
1661 phosphor::logging::log<phosphor::logging::level::ERR>(
1662 "ipmiOEMGetFscParameter: found illegal pid "
1663 "configurations");
1664 return ipmi::responseResponseError();
1665 }
1666 std::string type = std::get<std::string>(findClass->second);
1667 if (type == "fan")
1668 {
1669 auto findOutLimit = pid.find("OutLimitMin");
1670 if (findOutLimit == pid.end())
1671 {
1672 phosphor::logging::log<phosphor::logging::level::ERR>(
1673 "ipmiOEMGetFscParameter: found illegal pid "
1674 "configurations");
1675 return ipmi::responseResponseError();
1676 }
1677 // get the min out of all the offsets
1678 minOffset = std::min(
1679 minOffset,
1680 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1681 }
1682 }
1683 if (minOffset == std::numeric_limits<uint8_t>::max())
1684 {
1685 phosphor::logging::log<phosphor::logging::level::ERR>(
1686 "ipmiOEMGetFscParameter: found no fan configurations!");
1687 return ipmi::responseResponseError();
1688 }
1689
1690 return ipmi::responseSuccess(minOffset);
1691}
1692
1693ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1694{
1695 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1696 if (data.empty())
1697 {
1698
1699 phosphor::logging::log<phosphor::logging::level::ERR>(
1700 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1701 return ipmi::responseResponseError();
1702 }
1703
Vernon Mauery15419dd2019-05-24 09:40:30 -07001704 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001705 bool found = false;
1706 for (const auto& [path, pid] : data)
1707 {
1708 auto findClass = pid.find("Class");
1709 if (findClass == pid.end())
1710 {
1711
1712 phosphor::logging::log<phosphor::logging::level::ERR>(
1713 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1714 "configurations");
1715 return ipmi::responseResponseError();
1716 }
1717 std::string type = std::get<std::string>(findClass->second);
1718 if (type == "fan")
1719 {
1720 auto findOutLimit = pid.find("OutLimitMin");
1721 if (findOutLimit == pid.end())
1722 {
1723
1724 phosphor::logging::log<phosphor::logging::level::ERR>(
1725 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1726 "configurations");
1727 return ipmi::responseResponseError();
1728 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001729 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001730 path, pidConfigurationIface, "OutLimitMin",
1731 static_cast<double>(offset));
1732 found = true;
1733 }
1734 }
1735 if (!found)
1736 {
1737 phosphor::logging::log<phosphor::logging::level::ERR>(
1738 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1739 return ipmi::responseResponseError();
1740 }
1741
1742 return ipmi::responseSuccess();
1743}
1744
1745ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1746 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001747{
1748 constexpr const size_t disableLimiting = 0x0;
1749
Vernon Mauery15419dd2019-05-24 09:40:30 -07001750 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001751 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001752 {
James Feist09f6b602019-08-08 11:30:03 -07001753 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001754 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001755 {
James Feist09f6b602019-08-08 11:30:03 -07001756 pathName = exitAirPathName;
1757 }
1758 else if (param1 == legacyPCHSensorNumber)
1759 {
1760 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001761 }
1762 else
1763 {
James Feistacc8a4e2019-04-02 14:23:57 -07001764 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001765 }
James Feist09f6b602019-08-08 11:30:03 -07001766 std::string path = getConfigPath(pathName);
1767 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1768 pidConfigurationIface, "SetPoint",
1769 static_cast<double>(param2));
1770 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001771 }
James Feistacc8a4e2019-04-02 14:23:57 -07001772 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001773 {
James Feistacc8a4e2019-04-02 14:23:57 -07001774 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001775
1776 // must be greater than 50 based on eps
1777 if (cfm < 50 && cfm != disableLimiting)
1778 {
James Feistacc8a4e2019-04-02 14:23:57 -07001779 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001780 }
1781
1782 try
1783 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001784 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001785 cfmLimitIface, "Limit",
1786 static_cast<double>(cfm));
1787 }
1788 catch (sdbusplus::exception_t& e)
1789 {
1790 phosphor::logging::log<phosphor::logging::level::ERR>(
1791 "ipmiOEMSetFscParameter: can't set cfm setting!",
1792 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001793 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001794 }
James Feistacc8a4e2019-04-02 14:23:57 -07001795 return ipmi::responseSuccess();
1796 }
1797 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1798 {
1799 constexpr const size_t maxDomainCount = 8;
1800 uint8_t requestedDomainMask = param1;
1801 boost::container::flat_map data = getPidConfigs();
1802 if (data.empty())
1803 {
1804
1805 phosphor::logging::log<phosphor::logging::level::ERR>(
1806 "ipmiOEMSetFscParameter: found no pid configurations!");
1807 return ipmi::responseResponseError();
1808 }
1809 size_t count = 0;
1810 for (const auto& [path, pid] : data)
1811 {
1812 auto findClass = pid.find("Class");
1813 if (findClass == pid.end())
1814 {
1815
1816 phosphor::logging::log<phosphor::logging::level::ERR>(
1817 "ipmiOEMSetFscParameter: found illegal pid "
1818 "configurations");
1819 return ipmi::responseResponseError();
1820 }
1821 std::string type = std::get<std::string>(findClass->second);
1822 if (type == "fan")
1823 {
1824 if (requestedDomainMask & (1 << count))
1825 {
1826 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001827 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001828 pidConfigurationIface, "OutLimitMax",
1829 static_cast<double>(param2));
1830 }
1831 count++;
1832 }
1833 }
1834 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001835 }
1836 else
1837 {
1838 // todo other command parts possibly
1839 // tcontrol is handled in peci now
1840 // fan speed offset not implemented yet
1841 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001842 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001843 }
1844}
1845
James Feistacc8a4e2019-04-02 14:23:57 -07001846ipmi::RspType<
1847 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1848 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001849{
James Feist09f6b602019-08-08 11:30:03 -07001850 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001851
Vernon Mauery15419dd2019-05-24 09:40:30 -07001852 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001853 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001854 {
James Feistacc8a4e2019-04-02 14:23:57 -07001855 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001856 {
James Feistacc8a4e2019-04-02 14:23:57 -07001857 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001858 }
1859
James Feist09f6b602019-08-08 11:30:03 -07001860 std::string pathName;
1861
1862 if (*param == legacyExitAirSensorNumber)
1863 {
1864 pathName = exitAirPathName;
1865 }
1866 else if (*param == legacyPCHSensorNumber)
1867 {
1868 pathName = pchPathName;
1869 }
1870 else
James Feistfaa4f222019-03-21 16:21:55 -07001871 {
James Feistacc8a4e2019-04-02 14:23:57 -07001872 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001873 }
James Feist09f6b602019-08-08 11:30:03 -07001874
1875 uint8_t setpoint = legacyDefaultSetpoint;
1876 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001877 if (path.size())
1878 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001879 Value val = ipmi::getDbusProperty(
1880 *dbus, "xyz.openbmc_project.EntityManager", path,
1881 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001882 setpoint = std::floor(std::get<double>(val) + 0.5);
1883 }
1884
1885 // old implementation used to return the "default" and current, we
1886 // don't make the default readily available so just make both the
1887 // same
James Feistfaa4f222019-03-21 16:21:55 -07001888
James Feistacc8a4e2019-04-02 14:23:57 -07001889 return ipmi::responseSuccess(
1890 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001891 }
James Feistacc8a4e2019-04-02 14:23:57 -07001892 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1893 {
1894 constexpr const size_t maxDomainCount = 8;
1895
1896 if (!param)
1897 {
1898 return ipmi::responseReqDataLenInvalid();
1899 }
1900 uint8_t requestedDomain = *param;
1901 if (requestedDomain >= maxDomainCount)
1902 {
1903 return ipmi::responseInvalidFieldRequest();
1904 }
1905
1906 boost::container::flat_map data = getPidConfigs();
1907 if (data.empty())
1908 {
1909 phosphor::logging::log<phosphor::logging::level::ERR>(
1910 "ipmiOEMGetFscParameter: found no pid configurations!");
1911 return ipmi::responseResponseError();
1912 }
1913 size_t count = 0;
1914 for (const auto& [_, pid] : data)
1915 {
1916 auto findClass = pid.find("Class");
1917 if (findClass == pid.end())
1918 {
1919 phosphor::logging::log<phosphor::logging::level::ERR>(
1920 "ipmiOEMGetFscParameter: found illegal pid "
1921 "configurations");
1922 return ipmi::responseResponseError();
1923 }
1924 std::string type = std::get<std::string>(findClass->second);
1925 if (type == "fan")
1926 {
1927 if (requestedDomain == count)
1928 {
1929 auto findOutLimit = pid.find("OutLimitMax");
1930 if (findOutLimit == pid.end())
1931 {
1932 phosphor::logging::log<phosphor::logging::level::ERR>(
1933 "ipmiOEMGetFscParameter: found illegal pid "
1934 "configurations");
1935 return ipmi::responseResponseError();
1936 }
1937
1938 return ipmi::responseSuccess(
1939 static_cast<uint8_t>(std::floor(
1940 std::get<double>(findOutLimit->second) + 0.5)));
1941 }
1942 else
1943 {
1944 count++;
1945 }
1946 }
1947 }
1948
1949 return ipmi::responseInvalidFieldRequest();
1950 }
1951 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001952 {
1953
1954 /*
1955 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001956 previous behavior didn't seem to prevent this, ignore the check for
1957 now.
James Feist5f957ca2019-03-14 15:33:55 -07001958
James Feistacc8a4e2019-04-02 14:23:57 -07001959 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001960 {
1961 phosphor::logging::log<phosphor::logging::level::ERR>(
1962 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001963 return IPMI_CC_REQ_DATA_LEN_INVALID;
1964 }
1965 */
1966 Value cfmLimit;
1967 Value cfmMaximum;
1968 try
1969 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001970 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001971 cfmLimitSettingPath, cfmLimitIface,
1972 "Limit");
1973 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001974 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001975 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1976 }
1977 catch (sdbusplus::exception_t& e)
1978 {
1979 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001980 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001981 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001982 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001983 }
1984
James Feistacc8a4e2019-04-02 14:23:57 -07001985 double cfmMax = std::get<double>(cfmMaximum);
1986 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001987
James Feistacc8a4e2019-04-02 14:23:57 -07001988 cfmLim = std::floor(cfmLim + 0.5);
1989 cfmMax = std::floor(cfmMax + 0.5);
1990 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1991 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001992
James Feistacc8a4e2019-04-02 14:23:57 -07001993 return ipmi::responseSuccess(
1994 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001995 }
James Feistacc8a4e2019-04-02 14:23:57 -07001996
James Feist5f957ca2019-03-14 15:33:55 -07001997 else
1998 {
1999 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002000 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002001 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002002 }
2003}
2004
Cheng C Yang773703a2019-08-15 09:41:11 +08002005using crConfigVariant =
2006 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2007
2008int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2009 const crConfigVariant& value,
2010 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2011{
2012 boost::system::error_code ec;
2013 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002014 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002015 "/xyz/openbmc_project/control/power_supply_redundancy",
2016 "org.freedesktop.DBus.Properties", "Set",
2017 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2018 if (ec)
2019 {
2020 phosphor::logging::log<phosphor::logging::level::ERR>(
2021 "Failed to set dbus property to cold redundancy");
2022 return -1;
2023 }
2024
2025 return 0;
2026}
2027
2028int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2029 crConfigVariant& value,
2030 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2031{
2032 boost::system::error_code ec;
2033 value = ctx->bus->yield_method_call<crConfigVariant>(
James Feist28c72902019-09-16 10:34:07 -07002034 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002035 "/xyz/openbmc_project/control/power_supply_redundancy",
2036 "org.freedesktop.DBus.Properties", "Get",
2037 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2038 if (ec)
2039 {
2040 phosphor::logging::log<phosphor::logging::level::ERR>(
2041 "Failed to get dbus property to cold redundancy");
2042 return -1;
2043 }
2044 return 0;
2045}
2046
2047uint8_t getPSUCount(void)
2048{
2049 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2050 ipmi::Value num;
2051 try
2052 {
2053 num = ipmi::getDbusProperty(
2054 *dbus, "xyz.openbmc_project.PSURedundancy",
2055 "/xyz/openbmc_project/control/power_supply_redundancy",
2056 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2057 }
2058 catch (sdbusplus::exception_t& e)
2059 {
2060 phosphor::logging::log<phosphor::logging::level::ERR>(
2061 "Failed to get PSUNumber property from dbus interface");
2062 return 0;
2063 }
2064 uint8_t* pNum = std::get_if<uint8_t>(&num);
2065 if (!pNum)
2066 {
2067 phosphor::logging::log<phosphor::logging::level::ERR>(
2068 "Error to get PSU Number");
2069 return 0;
2070 }
2071 return *pNum;
2072}
2073
2074bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2075{
2076 if (conf.size() < num)
2077 {
2078 phosphor::logging::log<phosphor::logging::level::ERR>(
2079 "Invalid PSU Ranking");
2080 return false;
2081 }
2082 std::set<uint8_t> confSet;
2083 for (uint8_t i = 0; i < num; i++)
2084 {
2085 if (conf[i] > num)
2086 {
2087 phosphor::logging::log<phosphor::logging::level::ERR>(
2088 "PSU Ranking is larger than current PSU number");
2089 return false;
2090 }
2091 confSet.emplace(conf[i]);
2092 }
2093
2094 if (confSet.size() != num)
2095 {
2096 phosphor::logging::log<phosphor::logging::level::ERR>(
2097 "duplicate PSU Ranking");
2098 return false;
2099 }
2100 return true;
2101}
2102
2103enum class crParameter
2104{
2105 crStatus = 0,
2106 crFeature = 1,
2107 rotationFeature = 2,
2108 rotationAlgo = 3,
2109 rotationPeriod = 4,
2110 numOfPSU = 5
2111};
2112
2113constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2114static const constexpr uint32_t oneDay = 0x15180;
2115static const constexpr uint32_t oneMonth = 0xf53700;
2116static const constexpr uint8_t userSpecific = 0x01;
2117static const constexpr uint8_t crSetCompleted = 0;
2118ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2119 uint8_t parameter,
2120 ipmi::message::Payload& payload)
2121{
2122 switch (static_cast<crParameter>(parameter))
2123 {
2124 case crParameter::crFeature:
2125 {
2126 uint8_t param1;
2127 if (payload.unpack(param1) || !payload.fullyUnpacked())
2128 {
2129 return ipmi::responseReqDataLenInvalid();
2130 }
2131 // ColdRedundancy Enable can only be true or flase
2132 if (param1 > 1)
2133 {
2134 return ipmi::responseInvalidFieldRequest();
2135 }
2136 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2137 static_cast<bool>(param1)))
2138 {
2139 return ipmi::responseResponseError();
2140 }
2141 break;
2142 }
2143 case crParameter::rotationFeature:
2144 {
2145 uint8_t param1;
2146 if (payload.unpack(param1) || !payload.fullyUnpacked())
2147 {
2148 return ipmi::responseReqDataLenInvalid();
2149 }
2150 // Rotation Enable can only be true or false
2151 if (param1 > 1)
2152 {
2153 return ipmi::responseInvalidFieldRequest();
2154 }
2155 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2156 {
2157 return ipmi::responseResponseError();
2158 }
2159 break;
2160 }
2161 case crParameter::rotationAlgo:
2162 {
2163 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2164 std::string algoName;
2165 uint8_t param1;
2166 if (payload.unpack(param1))
2167 {
2168 return ipmi::responseReqDataLenInvalid();
2169 }
2170 switch (param1)
2171 {
2172 case 0:
2173 algoName = "xyz.openbmc_project.Control."
2174 "PowerSupplyRedundancy.Algo.bmcSpecific";
2175 break;
2176 case 1:
2177 algoName = "xyz.openbmc_project.Control."
2178 "PowerSupplyRedundancy.Algo.userSpecific";
2179 break;
2180 default:
2181 return ipmi::responseInvalidFieldRequest();
2182 }
2183 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2184 {
2185 return ipmi::responseResponseError();
2186 }
2187
2188 uint8_t numberOfPSU = getPSUCount();
2189 if (!numberOfPSU)
2190 {
2191 return ipmi::responseResponseError();
2192 }
2193 std::vector<uint8_t> rankOrder;
2194
2195 if (param1 == userSpecific)
2196 {
2197 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2198 {
2199 ipmi::responseReqDataLenInvalid();
2200 }
Yong Li83315132019-10-23 17:42:24 +08002201 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002202 {
2203 return ipmi::responseReqDataLenInvalid();
2204 }
2205
2206 if (!validateCRAlgo(rankOrder, numberOfPSU))
2207 {
2208 return ipmi::responseInvalidFieldRequest();
2209 }
2210 }
2211 else
2212 {
2213 if (rankOrder.size() > 0)
2214 {
2215 return ipmi::responseReqDataLenInvalid();
2216 }
2217 for (uint8_t i = 1; i <= numberOfPSU; i++)
2218 {
2219 rankOrder.emplace_back(i);
2220 }
2221 }
2222 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2223 {
2224 return ipmi::responseResponseError();
2225 }
2226 break;
2227 }
2228 case crParameter::rotationPeriod:
2229 {
2230 // Minimum Rotation period is One day (86400 seconds) and Max
2231 // Rotation Period is 6 month (0xf53700 seconds)
2232 uint32_t period;
2233 if (payload.unpack(period) || !payload.fullyUnpacked())
2234 {
2235 return ipmi::responseReqDataLenInvalid();
2236 }
2237 if ((period < oneDay) || (period > oneMonth))
2238 {
2239 return ipmi::responseInvalidFieldRequest();
2240 }
2241 if (setCRConfig(ctx, "PeriodOfRotation", period))
2242 {
2243 return ipmi::responseResponseError();
2244 }
2245 break;
2246 }
2247 default:
2248 {
2249 return ipmi::response(ccParameterNotSupported);
2250 }
2251 }
2252
2253 // TODO Halfwidth needs to set SetInProgress
2254 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002255 std::string("xyz.openbmc_project.Control."
2256 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002257 {
2258 return ipmi::responseResponseError();
2259 }
2260 return ipmi::responseSuccess(crSetCompleted);
2261}
2262
Yong Li83315132019-10-23 17:42:24 +08002263ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002264 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2265{
2266 crConfigVariant value;
2267 switch (static_cast<crParameter>(parameter))
2268 {
2269 case crParameter::crStatus:
2270 {
2271 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2272 {
2273 return ipmi::responseResponseError();
2274 }
2275 std::string* pStatus = std::get_if<std::string>(&value);
2276 if (!pStatus)
2277 {
2278 phosphor::logging::log<phosphor::logging::level::ERR>(
2279 "Error to get ColdRedundancyStatus property");
2280 return ipmi::responseResponseError();
2281 }
2282 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2283 auto status =
2284 server::PowerSupplyRedundancy::convertStatusFromString(
2285 *pStatus);
2286 switch (status)
2287 {
2288 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002289 return ipmi::responseSuccess(parameter,
2290 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002291
2292 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002293 return ipmi::responseSuccess(parameter,
2294 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002295 default:
2296 phosphor::logging::log<phosphor::logging::level::ERR>(
2297 "Error to get valid status");
2298 return ipmi::responseResponseError();
2299 }
2300 }
2301 case crParameter::crFeature:
2302 {
2303 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2304 {
2305 return ipmi::responseResponseError();
2306 }
2307 bool* pResponse = std::get_if<bool>(&value);
2308 if (!pResponse)
2309 {
2310 phosphor::logging::log<phosphor::logging::level::ERR>(
2311 "Error to get ColdRedundancyEnable property");
2312 return ipmi::responseResponseError();
2313 }
2314
Cheng C Yangf41e3342019-09-10 04:47:23 +08002315 return ipmi::responseSuccess(parameter,
2316 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002317 }
2318 case crParameter::rotationFeature:
2319 {
2320 if (getCRConfig(ctx, "RotationEnabled", value))
2321 {
2322 return ipmi::responseResponseError();
2323 }
2324 bool* pResponse = std::get_if<bool>(&value);
2325 if (!pResponse)
2326 {
2327 phosphor::logging::log<phosphor::logging::level::ERR>(
2328 "Error to get RotationEnabled property");
2329 return ipmi::responseResponseError();
2330 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002331 return ipmi::responseSuccess(parameter,
2332 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002333 }
2334 case crParameter::rotationAlgo:
2335 {
2336 if (getCRConfig(ctx, "RotationAlgorithm", value))
2337 {
2338 return ipmi::responseResponseError();
2339 }
2340
2341 std::string* pAlgo = std::get_if<std::string>(&value);
2342 if (!pAlgo)
2343 {
2344 phosphor::logging::log<phosphor::logging::level::ERR>(
2345 "Error to get RotationAlgorithm property");
2346 return ipmi::responseResponseError();
2347 }
Yong Li83315132019-10-23 17:42:24 +08002348 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002349 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2350 auto algo =
2351 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002352
Cheng C Yang773703a2019-08-15 09:41:11 +08002353 switch (algo)
2354 {
2355 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002356 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002357 break;
2358 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002359 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002360 break;
2361 default:
2362 phosphor::logging::log<phosphor::logging::level::ERR>(
2363 "Error to get valid algo");
2364 return ipmi::responseResponseError();
2365 }
2366
2367 if (getCRConfig(ctx, "RotationRankOrder", value))
2368 {
2369 return ipmi::responseResponseError();
2370 }
2371 std::vector<uint8_t>* pResponse =
2372 std::get_if<std::vector<uint8_t>>(&value);
2373 if (!pResponse)
2374 {
2375 phosphor::logging::log<phosphor::logging::level::ERR>(
2376 "Error to get RotationRankOrder property");
2377 return ipmi::responseResponseError();
2378 }
Yong Li83315132019-10-23 17:42:24 +08002379
Cheng C Yang773703a2019-08-15 09:41:11 +08002380 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002381 std::back_inserter(response));
2382
Cheng C Yangf41e3342019-09-10 04:47:23 +08002383 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002384 }
2385 case crParameter::rotationPeriod:
2386 {
2387 if (getCRConfig(ctx, "PeriodOfRotation", value))
2388 {
2389 return ipmi::responseResponseError();
2390 }
2391 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2392 if (!pResponse)
2393 {
2394 phosphor::logging::log<phosphor::logging::level::ERR>(
2395 "Error to get RotationAlgorithm property");
2396 return ipmi::responseResponseError();
2397 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002398 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002399 }
2400 case crParameter::numOfPSU:
2401 {
2402 uint8_t numberOfPSU = getPSUCount();
2403 if (!numberOfPSU)
2404 {
2405 return ipmi::responseResponseError();
2406 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002407 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002408 }
2409 default:
2410 {
2411 return ipmi::response(ccParameterNotSupported);
2412 }
2413 }
2414}
2415
Zhu, Yungebe560b02019-04-21 21:19:21 -04002416ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2417 uint8_t faultState,
2418 uint8_t faultGroup,
2419 std::array<uint8_t, 8>& ledStateData)
2420{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002421 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2422 static const std::array<std::string, maxFaultType> faultNames = {
2423 "faultFan", "faultTemp", "faultPower",
2424 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002425
2426 constexpr uint8_t maxFaultSource = 0x4;
2427 constexpr uint8_t skipLEDs = 0xFF;
2428 constexpr uint8_t pinSize = 64;
2429 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002430 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002431
Zhikui Rence4e73f2019-12-06 13:59:47 -08002432 // same pin names need to be defined in dts file
2433 static const std::array<std::array<std::string, groupSize>, groupNum>
2434 faultLedPinNames = {{
2435 "LED_CPU1_CH1_DIMM1_FAULT",
2436 "LED_CPU1_CH1_DIMM2_FAULT",
2437 "LED_CPU1_CH2_DIMM1_FAULT",
2438 "LED_CPU1_CH2_DIMM2_FAULT",
2439 "LED_CPU1_CH3_DIMM1_FAULT",
2440 "LED_CPU1_CH3_DIMM2_FAULT",
2441 "LED_CPU1_CH4_DIMM1_FAULT",
2442 "LED_CPU1_CH4_DIMM2_FAULT",
2443 "LED_CPU1_CH5_DIMM1_FAULT",
2444 "LED_CPU1_CH5_DIMM2_FAULT",
2445 "LED_CPU1_CH6_DIMM1_FAULT",
2446 "LED_CPU1_CH6_DIMM2_FAULT",
2447 "",
2448 "",
2449 "",
2450 "", // end of group1
2451 "LED_CPU2_CH1_DIMM1_FAULT",
2452 "LED_CPU2_CH1_DIMM2_FAULT",
2453 "LED_CPU2_CH2_DIMM1_FAULT",
2454 "LED_CPU2_CH2_DIMM2_FAULT",
2455 "LED_CPU2_CH3_DIMM1_FAULT",
2456 "LED_CPU2_CH3_DIMM2_FAULT",
2457 "LED_CPU2_CH4_DIMM1_FAULT",
2458 "LED_CPU2_CH4_DIMM2_FAULT",
2459 "LED_CPU2_CH5_DIMM1_FAULT",
2460 "LED_CPU2_CH5_DIMM2_FAULT",
2461 "LED_CPU2_CH6_DIMM1_FAULT",
2462 "LED_CPU2_CH6_DIMM2_FAULT",
2463 "",
2464 "",
2465 "",
2466 "", // endof group2
2467 "LED_CPU3_CH1_DIMM1_FAULT",
2468 "LED_CPU3_CH1_DIMM2_FAULT",
2469 "LED_CPU3_CH2_DIMM1_FAULT",
2470 "LED_CPU3_CH2_DIMM2_FAULT",
2471 "LED_CPU3_CH3_DIMM1_FAULT",
2472 "LED_CPU3_CH3_DIMM2_FAULT",
2473 "LED_CPU3_CH4_DIMM1_FAULT",
2474 "LED_CPU3_CH4_DIMM2_FAULT",
2475 "LED_CPU3_CH5_DIMM1_FAULT",
2476 "LED_CPU3_CH5_DIMM2_FAULT",
2477 "LED_CPU3_CH6_DIMM1_FAULT",
2478 "LED_CPU3_CH6_DIMM2_FAULT",
2479 "",
2480 "",
2481 "",
2482 "", // end of group3
2483 "LED_CPU4_CH1_DIMM1_FAULT",
2484 "LED_CPU4_CH1_DIMM2_FAULT",
2485 "LED_CPU4_CH2_DIMM1_FAULT",
2486 "LED_CPU4_CH2_DIMM2_FAULT",
2487 "LED_CPU4_CH3_DIMM1_FAULT",
2488 "LED_CPU4_CH3_DIMM2_FAULT",
2489 "LED_CPU4_CH4_DIMM1_FAULT",
2490 "LED_CPU4_CH4_DIMM2_FAULT",
2491 "LED_CPU4_CH5_DIMM1_FAULT",
2492 "LED_CPU4_CH5_DIMM2_FAULT",
2493 "LED_CPU4_CH6_DIMM1_FAULT",
2494 "LED_CPU4_CH6_DIMM2_FAULT",
2495 "",
2496 "",
2497 "",
2498 "", // end of group4
2499 "LED_FAN1_FAULT",
2500 "LED_FAN2_FAULT",
2501 "LED_FAN3_FAULT",
2502 "LED_FAN4_FAULT",
2503 "LED_FAN5_FAULT",
2504 "LED_FAN6_FAULT",
2505 "LED_FAN7_FAULT",
2506 "LED_FAN8_FAULT",
2507 "",
2508 "",
2509 "",
2510 "",
2511 "",
2512 "",
2513 "",
2514 "" // end of group5
2515 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002516
Zhikui Rence4e73f2019-12-06 13:59:47 -08002517 // Validate the source, fault type --
2518 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2519 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2520 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2521 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2522 // definition differs based on fault type (Byte 2)
2523 // Type Fan=> Group: 0=FanGroupID, FF-not used
2524 // Byte 5-11 00h, not used
2525 // Byte12 FanLedState [7:0]-Fans 7:0
2526 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2527 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2528 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2529 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2530 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2531 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2532 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2533 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002534 if ((sourceId >= maxFaultSource) ||
2535 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2536 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2537 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2538 {
2539 return ipmi::responseParmOutOfRange();
2540 }
2541
Zhikui Rence4e73f2019-12-06 13:59:47 -08002542 size_t pinGroupOffset = 0;
2543 size_t pinGroupMax = pinSize / groupSize;
2544 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002545 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002546 pinGroupOffset = 4;
2547 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002548 }
2549
2550 switch (RemoteFaultType(faultType))
2551 {
2552 case (RemoteFaultType::fan):
2553 case (RemoteFaultType::memory):
2554 {
2555 if (faultGroup == skipLEDs)
2556 {
2557 return ipmi::responseSuccess();
2558 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002559 // calculate led state bit filed count, each byte has 8bits
2560 // the maximum bits will be 8 * 8 bits
2561 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002562
2563 // assemble ledState
2564 uint64_t ledState = 0;
2565 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002566 for (int i = 0; i < sizeof(ledStateData); i++)
2567 {
2568 ledState = (uint64_t)(ledState << 8);
2569 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2570 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002571 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002572
Zhikui Rence4e73f2019-12-06 13:59:47 -08002573 for (int group = 0; group < pinGroupMax; group++)
2574 {
2575 for (int i = 0; i < groupSize; i++)
2576 { // skip non-existing pins
2577 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2578 {
2579 continue;
2580 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002581
Zhikui Rence4e73f2019-12-06 13:59:47 -08002582 gpiod::line line = gpiod::find_line(
2583 faultLedPinNames[group + pinGroupOffset][i]);
2584 if (!line)
2585 {
2586 phosphor::logging::log<phosphor::logging::level::ERR>(
2587 "Not Find Led Gpio Device!",
2588 phosphor::logging::entry(
2589 "DEVICE=%s",
2590 faultLedPinNames[group + pinGroupOffset][i]
2591 .c_str()));
2592 hasError = true;
2593 continue;
2594 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002595
Zhikui Rence4e73f2019-12-06 13:59:47 -08002596 bool activeHigh =
2597 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2598 try
2599 {
2600 line.request(
2601 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2602 activeHigh
2603 ? 0
2604 : gpiod::line_request::FLAG_ACTIVE_LOW});
2605 line.set_value(ledStateBits[i + group * groupSize]);
2606 }
2607 catch (std::system_error&)
2608 {
2609 phosphor::logging::log<phosphor::logging::level::ERR>(
2610 "Error write Led Gpio Device!",
2611 phosphor::logging::entry(
2612 "DEVICE=%s",
2613 faultLedPinNames[group + pinGroupOffset][i]
2614 .c_str()));
2615 hasError = true;
2616 continue;
2617 }
2618 } // for int i
2619 }
2620 if (hasError)
2621 {
2622 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002623 }
2624 break;
2625 }
2626 default:
2627 {
2628 // now only support two fault types
2629 return ipmi::responseParmOutOfRange();
2630 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002631 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002632 return ipmi::responseSuccess();
2633}
2634
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302635ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2636{
2637 uint8_t prodId = 0;
2638 try
2639 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002640 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302641 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002642 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302643 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2644 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002645 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302646 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2647 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2648 }
2649 catch (std::exception& e)
2650 {
2651 phosphor::logging::log<phosphor::logging::level::ERR>(
2652 "ipmiOEMReadBoardProductId: Product ID read failed!",
2653 phosphor::logging::entry("ERR=%s", e.what()));
2654 }
2655 return ipmi::responseSuccess(prodId);
2656}
2657
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302658/** @brief implements the get security mode command
2659 * @param ctx - ctx pointer
2660 *
2661 * @returns IPMI completion code with following data
2662 * - restriction mode value - As specified in
2663 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2664 * - special mode value - As specified in
2665 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2666 */
2667ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2668{
2669 namespace securityNameSpace =
2670 sdbusplus::xyz::openbmc_project::Control::Security::server;
2671 uint8_t restrictionModeValue = 0;
2672 uint8_t specialModeValue = 0;
2673
2674 boost::system::error_code ec;
2675 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002676 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302677 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2678 restricionModeProperty);
2679 if (ec)
2680 {
2681 phosphor::logging::log<phosphor::logging::level::ERR>(
2682 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2683 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2684 return ipmi::responseUnspecifiedError();
2685 }
2686 restrictionModeValue = static_cast<uint8_t>(
2687 securityNameSpace::RestrictionMode::convertModesFromString(
2688 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302689 auto varSpecialMode =
2690 ctx->bus->yield_method_call<std::variant<std::string>>(
2691 ctx->yield, ec, specialModeService, specialModeBasePath,
2692 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2693 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302694 if (ec)
2695 {
2696 phosphor::logging::log<phosphor::logging::level::ERR>(
2697 "ipmiGetSecurityMode: failed to get SpecialMode property",
2698 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2699 // fall through, let us not worry about SpecialMode property, which is
2700 // not required in user scenario
2701 }
2702 else
2703 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302704 specialModeValue = static_cast<uint8_t>(
2705 securityNameSpace::SpecialMode::convertModesFromString(
2706 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302707 }
2708 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2709}
2710
2711/** @brief implements the set security mode command
2712 * Command allows to upgrade the restriction mode and won't allow
2713 * to downgrade from system interface
2714 * @param ctx - ctx pointer
2715 * @param restrictionMode - restriction mode value to be set.
2716 *
2717 * @returns IPMI completion code
2718 */
2719ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302720 uint8_t restrictionMode,
2721 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302722{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302723#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2724 if (specialMode)
2725 {
2726 return ipmi::responseReqDataLenInvalid();
2727 }
2728#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302729 namespace securityNameSpace =
2730 sdbusplus::xyz::openbmc_project::Control::Security::server;
2731
2732 ChannelInfo chInfo;
2733 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2734 {
2735 phosphor::logging::log<phosphor::logging::level::ERR>(
2736 "ipmiSetSecurityMode: Failed to get Channel Info",
2737 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2738 return ipmi::responseUnspecifiedError();
2739 }
2740 auto reqMode =
2741 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2742
2743 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2744 (reqMode >
2745 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2746 {
2747 return ipmi::responseInvalidFieldRequest();
2748 }
2749
2750 boost::system::error_code ec;
2751 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002752 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302753 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2754 restricionModeProperty);
2755 if (ec)
2756 {
2757 phosphor::logging::log<phosphor::logging::level::ERR>(
2758 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2759 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2760 return ipmi::responseUnspecifiedError();
2761 }
2762 auto currentRestrictionMode =
2763 securityNameSpace::RestrictionMode::convertModesFromString(
2764 std::get<std::string>(varRestrMode));
2765
2766 if (chInfo.mediumType !=
2767 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2768 currentRestrictionMode > reqMode)
2769 {
2770 phosphor::logging::log<phosphor::logging::level::ERR>(
2771 "ipmiSetSecurityMode - Downgrading security mode not supported "
2772 "through system interface",
2773 phosphor::logging::entry(
2774 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2775 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2776 return ipmi::responseCommandNotAvailable();
2777 }
2778
2779 ec.clear();
2780 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002781 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302782 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2783 restricionModeProperty,
2784 static_cast<std::variant<std::string>>(
2785 securityNameSpace::convertForMessage(reqMode)));
2786
2787 if (ec)
2788 {
2789 phosphor::logging::log<phosphor::logging::level::ERR>(
2790 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2791 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2792 return ipmi::responseUnspecifiedError();
2793 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302794
2795#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2796 if (specialMode)
2797 {
2798 ec.clear();
2799 ctx->bus->yield_method_call<>(
2800 ctx->yield, ec, specialModeService, specialModeBasePath,
2801 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2802 specialModeProperty,
2803 static_cast<std::variant<std::string>>(
2804 securityNameSpace::convertForMessage(
2805 static_cast<securityNameSpace::SpecialMode::Modes>(
2806 specialMode.value()))));
2807
2808 if (ec)
2809 {
2810 phosphor::logging::log<phosphor::logging::level::ERR>(
2811 "ipmiSetSecurityMode: failed to set SpecialMode property",
2812 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2813 return ipmi::responseUnspecifiedError();
2814 }
2815 }
2816#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302817 return ipmi::responseSuccess();
2818}
2819
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002820ipmi::RspType<uint8_t /* restore status */>
2821 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2822{
2823 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2824
2825 if (clr != expClr)
2826 {
2827 return ipmi::responseInvalidFieldRequest();
2828 }
2829 constexpr uint8_t cmdStatus = 0;
2830 constexpr uint8_t cmdDefaultRestore = 0xaa;
2831 constexpr uint8_t cmdFullRestore = 0xbb;
2832 constexpr uint8_t cmdFormat = 0xcc;
2833
2834 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2835
2836 switch (cmd)
2837 {
2838 case cmdStatus:
2839 break;
2840 case cmdDefaultRestore:
2841 case cmdFullRestore:
2842 case cmdFormat:
2843 {
2844 // write file to rwfs root
2845 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2846 std::ofstream restoreFile(restoreOpFname);
2847 if (!restoreFile)
2848 {
2849 return ipmi::responseUnspecifiedError();
2850 }
2851 restoreFile << value << "\n";
2852 break;
2853 }
2854 default:
2855 return ipmi::responseInvalidFieldRequest();
2856 }
2857
2858 constexpr uint8_t restorePending = 0;
2859 constexpr uint8_t restoreComplete = 1;
2860
2861 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2862 ? restorePending
2863 : restoreComplete;
2864 return ipmi::responseSuccess(restoreStatus);
2865}
2866
Chen Yugang39736d52019-07-12 16:24:33 +08002867ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2868{
2869 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002870 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002871
2872 try
2873 {
2874 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2875 std::string service =
2876 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2877 Value variant =
2878 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2879 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2880
2881 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2882 std::get<std::string>(variant)))
2883 {
2884 case nmi::NMISource::BMCSourceSignal::None:
2885 bmcSource = static_cast<uint8_t>(NmiSource::none);
2886 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002887 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2888 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002889 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002890 case nmi::NMISource::BMCSourceSignal::Watchdog:
2891 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002892 break;
2893 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2894 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2895 break;
2896 case nmi::NMISource::BMCSourceSignal::MemoryError:
2897 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2898 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002899 case nmi::NMISource::BMCSourceSignal::PciBusError:
2900 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002901 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002902 case nmi::NMISource::BMCSourceSignal::PCH:
2903 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002904 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002905 case nmi::NMISource::BMCSourceSignal::Chipset:
2906 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002907 break;
2908 default:
2909 phosphor::logging::log<phosphor::logging::level::ERR>(
2910 "NMI source: invalid property!",
2911 phosphor::logging::entry(
2912 "PROP=%s", std::get<std::string>(variant).c_str()));
2913 return ipmi::responseResponseError();
2914 }
2915 }
2916 catch (sdbusplus::exception::SdBusError& e)
2917 {
2918 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2919 return ipmi::responseResponseError();
2920 }
2921
2922 return ipmi::responseSuccess(bmcSource);
2923}
2924
2925ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2926{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002927 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002928
2929 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2930 nmi::NMISource::BMCSourceSignal::None;
2931
2932 switch (NmiSource(sourceId))
2933 {
2934 case NmiSource::none:
2935 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2936 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002937 case NmiSource::frontPanelButton:
2938 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08002939 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002940 case NmiSource::watchdog:
2941 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08002942 break;
2943 case NmiSource::chassisCmd:
2944 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2945 break;
2946 case NmiSource::memoryError:
2947 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2948 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002949 case NmiSource::pciBusError:
2950 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08002951 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002952 case NmiSource::pch:
2953 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08002954 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002955 case NmiSource::chipset:
2956 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08002957 break;
2958 default:
2959 phosphor::logging::log<phosphor::logging::level::ERR>(
2960 "NMI source: invalid property!");
2961 return ipmi::responseResponseError();
2962 }
2963
2964 try
2965 {
2966 // keep NMI signal source
2967 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2968 std::string service =
2969 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08002970 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2971 oemNmiBmcSourceObjPathProp,
2972 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002973 // set Enabled property to inform NMI source handling
2974 // to trigger a NMI_OUT BSOD.
2975 // if it's triggered by NMI source property changed,
2976 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2977 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2978 {
2979 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2980 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2981 static_cast<bool>(true));
2982 }
Chen Yugang39736d52019-07-12 16:24:33 +08002983 }
2984 catch (sdbusplus::exception_t& e)
2985 {
2986 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2987 return ipmi::responseResponseError();
2988 }
2989
2990 return ipmi::responseSuccess();
2991}
2992
James Feist63efafa2019-07-24 12:39:21 -07002993namespace dimmOffset
2994{
2995constexpr const char* dimmPower = "DimmPower";
2996constexpr const char* staticCltt = "StaticCltt";
2997constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2998constexpr const char* offsetInterface =
2999 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3000constexpr const char* property = "DimmOffset";
3001
3002}; // namespace dimmOffset
3003
3004ipmi::RspType<>
3005 ipmiOEMSetDimmOffset(uint8_t type,
3006 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3007{
3008 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3009 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3010 {
3011 return ipmi::responseInvalidFieldRequest();
3012 }
3013
3014 if (data.empty())
3015 {
3016 return ipmi::responseInvalidFieldRequest();
3017 }
3018 nlohmann::json json;
3019
3020 std::ifstream jsonStream(dimmOffsetFile);
3021 if (jsonStream.good())
3022 {
3023 json = nlohmann::json::parse(jsonStream, nullptr, false);
3024 if (json.is_discarded())
3025 {
3026 json = nlohmann::json();
3027 }
3028 jsonStream.close();
3029 }
3030
3031 std::string typeName;
3032 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3033 {
3034 typeName = dimmOffset::dimmPower;
3035 }
3036 else
3037 {
3038 typeName = dimmOffset::staticCltt;
3039 }
3040
3041 nlohmann::json& field = json[typeName];
3042
3043 for (const auto& [index, value] : data)
3044 {
3045 field[index] = value;
3046 }
3047
3048 for (nlohmann::json& val : field)
3049 {
3050 if (val == nullptr)
3051 {
3052 val = static_cast<uint8_t>(0);
3053 }
3054 }
3055
3056 std::ofstream output(dimmOffsetFile);
3057 if (!output.good())
3058 {
3059 std::cerr << "Error writing json file\n";
3060 return ipmi::responseResponseError();
3061 }
3062
3063 output << json.dump(4);
3064
3065 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3066 {
3067 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3068
3069 std::variant<std::vector<uint8_t>> offsets =
3070 field.get<std::vector<uint8_t>>();
3071 auto call = bus->new_method_call(
3072 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3073 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3074 try
3075 {
3076 bus->call(call);
3077 }
3078 catch (sdbusplus::exception_t& e)
3079 {
3080 phosphor::logging::log<phosphor::logging::level::ERR>(
3081 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3082 phosphor::logging::entry("ERR=%s", e.what()));
3083 return ipmi::responseResponseError();
3084 }
3085 }
3086
3087 return ipmi::responseSuccess();
3088}
3089
3090ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3091{
3092
3093 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3094 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3095 {
3096 return ipmi::responseInvalidFieldRequest();
3097 }
3098
3099 std::ifstream jsonStream(dimmOffsetFile);
3100
3101 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3102 if (json.is_discarded())
3103 {
3104 std::cerr << "File error in " << dimmOffsetFile << "\n";
3105 return ipmi::responseResponseError();
3106 }
3107
3108 std::string typeName;
3109 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3110 {
3111 typeName = dimmOffset::dimmPower;
3112 }
3113 else
3114 {
3115 typeName = dimmOffset::staticCltt;
3116 }
3117
3118 auto it = json.find(typeName);
3119 if (it == json.end())
3120 {
3121 return ipmi::responseInvalidFieldRequest();
3122 }
3123
3124 if (it->size() <= index)
3125 {
3126 return ipmi::responseInvalidFieldRequest();
3127 }
3128
3129 uint8_t resp = it->at(index).get<uint8_t>();
3130 return ipmi::responseSuccess(resp);
3131}
3132
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003133namespace boot_options
3134{
3135
3136using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3137using IpmiValue = uint8_t;
3138constexpr auto ipmiDefault = 0;
3139
3140std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3141 {0x01, Source::Sources::Network},
3142 {0x02, Source::Sources::Disk},
3143 {0x05, Source::Sources::ExternalMedia},
3144 {0x0f, Source::Sources::RemovableMedia},
3145 {ipmiDefault, Source::Sources::Default}};
3146
3147std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003148 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003149
3150std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3151 {Source::Sources::Network, 0x01},
3152 {Source::Sources::Disk, 0x02},
3153 {Source::Sources::ExternalMedia, 0x05},
3154 {Source::Sources::RemovableMedia, 0x0f},
3155 {Source::Sources::Default, ipmiDefault}};
3156
3157std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003158 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003159
3160static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3161static constexpr auto bootSourceIntf =
3162 "xyz.openbmc_project.Control.Boot.Source";
3163static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3164static constexpr auto persistentObjPath =
3165 "/xyz/openbmc_project/control/host0/boot";
3166static constexpr auto oneTimePath =
3167 "/xyz/openbmc_project/control/host0/boot/one_time";
3168static constexpr auto bootSourceProp = "BootSource";
3169static constexpr auto bootModeProp = "BootMode";
3170static constexpr auto oneTimeBootEnableProp = "Enabled";
3171static constexpr auto httpBootMode =
3172 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3173
3174enum class BootOptionParameter : size_t
3175{
3176 setInProgress = 0x0,
3177 bootFlags = 0x5,
3178};
3179static constexpr uint8_t setComplete = 0x0;
3180static constexpr uint8_t setInProgress = 0x1;
3181static uint8_t transferStatus = setComplete;
3182static constexpr uint8_t setParmVersion = 0x01;
3183static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3184static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3185static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3186static constexpr uint8_t httpBoot = 0xd;
3187static constexpr uint8_t bootSourceMask = 0x3c;
3188
3189} // namespace boot_options
3190
3191ipmi::RspType<uint8_t, // version
3192 uint8_t, // param
3193 uint8_t, // data0, dependent on parameter
3194 std::optional<uint8_t> // data1, dependent on parameter
3195 >
3196 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3197{
3198 using namespace boot_options;
3199 uint8_t bootOption = 0;
3200
3201 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3202 {
3203 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3204 std::nullopt);
3205 }
3206
3207 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3208 {
3209 phosphor::logging::log<phosphor::logging::level::ERR>(
3210 "Unsupported parameter");
3211 return ipmi::responseResponseError();
3212 }
3213
3214 try
3215 {
3216 auto oneTimeEnabled = false;
3217 // read one time Enabled property
3218 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3219 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3220 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3221 enabledIntf, oneTimeBootEnableProp);
3222 oneTimeEnabled = std::get<bool>(variant);
3223
3224 // get BootSource and BootMode properties
3225 // according to oneTimeEnable
3226 auto bootObjPath = oneTimePath;
3227 if (oneTimeEnabled == false)
3228 {
3229 bootObjPath = persistentObjPath;
3230 }
3231
3232 service = getService(*dbus, bootModeIntf, bootObjPath);
3233 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3234 bootModeProp);
3235
3236 auto bootMode =
3237 Mode::convertModesFromString(std::get<std::string>(variant));
3238
3239 service = getService(*dbus, bootSourceIntf, bootObjPath);
3240 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3241 bootSourceProp);
3242
3243 if (std::get<std::string>(variant) == httpBootMode)
3244 {
3245 bootOption = httpBoot;
3246 }
3247 else
3248 {
3249 auto bootSource = Source::convertSourcesFromString(
3250 std::get<std::string>(variant));
3251 bootOption = sourceDbusToIpmi.at(bootSource);
3252 if (Source::Sources::Default == bootSource)
3253 {
3254 bootOption = modeDbusToIpmi.at(bootMode);
3255 }
3256 }
3257
3258 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3259 : setParmBootFlagsValidPermanent;
3260 bootOption <<= 2; // shift for responseconstexpr
3261 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3262 bootOption);
3263 }
3264 catch (sdbusplus::exception_t& e)
3265 {
3266 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3267 return ipmi::responseResponseError();
3268 }
3269}
3270
3271ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3272 std::optional<uint8_t> bootOption)
3273{
3274 using namespace boot_options;
3275 auto oneTimeEnabled = false;
3276
3277 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3278 {
3279 if (bootOption)
3280 {
3281 return ipmi::responseReqDataLenInvalid();
3282 }
3283
3284 if (transferStatus == setInProgress)
3285 {
3286 phosphor::logging::log<phosphor::logging::level::ERR>(
3287 "boot option set in progress!");
3288 return ipmi::responseResponseError();
3289 }
3290
3291 transferStatus = bootParam;
3292 return ipmi::responseSuccess();
3293 }
3294
3295 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3296 {
3297 phosphor::logging::log<phosphor::logging::level::ERR>(
3298 "Unsupported parameter");
3299 return ipmi::responseResponseError();
3300 }
3301
3302 if (!bootOption)
3303 {
3304 return ipmi::responseReqDataLenInvalid();
3305 }
3306
3307 if (((bootOption.value() & bootSourceMask) >> 2) !=
3308 httpBoot) // not http boot, exit
3309 {
3310 phosphor::logging::log<phosphor::logging::level::ERR>(
3311 "wrong boot option parameter!");
3312 return ipmi::responseParmOutOfRange();
3313 }
3314
3315 try
3316 {
3317 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3318 setParmBootFlagsPermanent;
3319
3320 // read one time Enabled property
3321 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3322 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3323 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3324 enabledIntf, oneTimeBootEnableProp);
3325 oneTimeEnabled = std::get<bool>(variant);
3326
3327 /*
3328 * Check if the current boot setting is onetime or permanent, if the
3329 * request in the command is otherwise, then set the "Enabled"
3330 * property in one_time object path to 'True' to indicate onetime
3331 * and 'False' to indicate permanent.
3332 *
3333 * Once the onetime/permanent setting is applied, then the bootMode
3334 * and bootSource is updated for the corresponding object.
3335 */
3336 if (permanent == oneTimeEnabled)
3337 {
3338 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3339 oneTimeBootEnableProp, !permanent);
3340 }
3341
3342 // set BootSource and BootMode properties
3343 // according to oneTimeEnable or persistent
3344 auto bootObjPath = oneTimePath;
3345 if (oneTimeEnabled == false)
3346 {
3347 bootObjPath = persistentObjPath;
3348 }
3349 std::string bootMode =
3350 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3351 std::string bootSource = httpBootMode;
3352
3353 service = getService(*dbus, bootModeIntf, bootObjPath);
3354 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3355 bootMode);
3356
3357 service = getService(*dbus, bootSourceIntf, bootObjPath);
3358 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3359 bootSourceProp, bootSource);
3360 }
3361 catch (sdbusplus::exception_t& e)
3362 {
3363 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3364 return ipmi::responseResponseError();
3365 }
3366
3367 return ipmi::responseSuccess();
3368}
3369
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003370using BasicVariantType =
3371 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3372 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3373 uint16_t, uint8_t, bool>;
3374using PropertyMapType =
3375 boost::container::flat_map<std::string, BasicVariantType>;
3376static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3377 "xyz.openbmc_project.Configuration.PSUPresence"};
3378int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3379 std::vector<uint64_t>& addrTable)
3380{
3381 boost::system::error_code ec;
3382 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3383 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3384 "/xyz/openbmc_project/object_mapper",
3385 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3386 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3387 if (ec)
3388 {
3389 phosphor::logging::log<phosphor::logging::level::ERR>(
3390 "Failed to set dbus property to cold redundancy");
3391 return -1;
3392 }
3393 for (const auto& object : subtree)
3394 {
3395 std::string pathName = object.first;
3396 for (const auto& serviceIface : object.second)
3397 {
3398 std::string serviceName = serviceIface.first;
3399
3400 ec.clear();
3401 PropertyMapType propMap =
3402 ctx->bus->yield_method_call<PropertyMapType>(
3403 ctx->yield, ec, serviceName, pathName,
3404 "org.freedesktop.DBus.Properties", "GetAll",
3405 "xyz.openbmc_project.Configuration.PSUPresence");
3406 if (ec)
3407 {
3408 phosphor::logging::log<phosphor::logging::level::ERR>(
3409 "Failed to set dbus property to cold redundancy");
3410 return -1;
3411 }
3412 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3413 auto psuAddress =
3414 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3415
3416 if (psuBus == nullptr || psuAddress == nullptr)
3417 {
3418 std::cerr << "error finding necessary "
3419 "entry in configuration\n";
3420 return -1;
3421 }
3422 bus = static_cast<uint8_t>(*psuBus);
3423 addrTable = *psuAddress;
3424 return 0;
3425 }
3426 }
3427 return -1;
3428}
3429
3430static const constexpr uint8_t addrOffset = 8;
3431static const constexpr uint8_t psuRevision = 0xd9;
3432static const constexpr uint8_t defaultPSUBus = 7;
3433// Second Minor, Primary Minor, Major
3434static const constexpr size_t verLen = 3;
3435ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3436{
3437 uint8_t bus = defaultPSUBus;
3438 std::vector<uint64_t> addrTable;
3439 std::vector<uint8_t> result;
3440 if (getPSUAddress(ctx, bus, addrTable))
3441 {
3442 std::cerr << "Failed to get PSU bus and address\n";
3443 return ipmi::responseResponseError();
3444 }
3445
3446 for (const auto& slaveAddr : addrTable)
3447 {
3448 std::vector<uint8_t> writeData = {psuRevision};
3449 std::vector<uint8_t> readBuf(verLen);
3450 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3451 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3452
3453 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3454 if (retI2C != ipmi::ccSuccess)
3455 {
3456 for (size_t idx = 0; idx < verLen; idx++)
3457 {
3458 result.emplace_back(0x00);
3459 }
3460 }
3461 else
3462 {
3463 for (const uint8_t& data : readBuf)
3464 {
3465 result.emplace_back(data);
3466 }
3467 }
3468 }
3469
3470 return ipmi::responseSuccess(result);
3471}
3472
AppaRao Puli28972062019-11-11 02:04:45 +05303473/** @brief implements the maximum size of
3474 * bridgeable messages used between KCS and
3475 * IPMB interfacesget security mode command.
3476 *
3477 * @returns IPMI completion code with following data
3478 * - KCS Buffer Size (In multiples of four bytes)
3479 * - IPMB Buffer Size (In multiples of four bytes)
3480 **/
3481ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3482{
3483 // for now this is hard coded; really this number is dependent on
3484 // the BMC kcs driver as well as the host kcs driver....
3485 // we can't know the latter.
3486 uint8_t kcsMaxBufferSize = 63 / 4;
3487 uint8_t ipmbMaxBufferSize = 128 / 4;
3488
3489 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3490}
3491
Jason M. Bills64796042018-10-03 16:51:55 -07003492static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003493{
3494 phosphor::logging::log<phosphor::logging::level::INFO>(
3495 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003496 ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003497 ipmiOEMWildcard,
3498 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003499
3500 ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003501 ipmiOEMWildcard,
3502 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003503
3504 ipmiPrintAndRegister(intel::netFnGeneral,
3505 intel::general::cmdGetChassisIdentifier, NULL,
3506 ipmiOEMGetChassisIdentifier,
3507 PRIVILEGE_USER); // get chassis identifier
3508
3509 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3510 NULL, ipmiOEMSetSystemGUID,
3511 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003512
3513 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003514 registerHandler(prioOemBase, intel::netFnGeneral,
3515 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3516 ipmiOEMDisableBMCSystemReset);
3517
Jason M. Billsb02bf092019-08-15 13:01:56 -07003518 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003519 registerHandler(prioOemBase, intel::netFnGeneral,
3520 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3521 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003522
Vernon Mauery98bbf692019-09-16 11:14:59 -07003523 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3524 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003525
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003526 registerHandler(prioOemBase, intel::netFnGeneral,
3527 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3528 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003529
Vernon Mauery98bbf692019-09-16 11:14:59 -07003530 ipmiPrintAndRegister(intel::netFnGeneral,
3531 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3532 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303533
Vernon Mauery98bbf692019-09-16 11:14:59 -07003534 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3535 intel::general::cmdSendEmbeddedFWUpdStatus,
3536 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303537
Vernon Mauery98bbf692019-09-16 11:14:59 -07003538 ipmiPrintAndRegister(intel::netFnGeneral,
3539 intel::general::cmdSetPowerRestoreDelay, NULL,
3540 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3541
3542 ipmiPrintAndRegister(intel::netFnGeneral,
3543 intel::general::cmdGetPowerRestoreDelay, NULL,
3544 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3545
3546 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3547 intel::general::cmdSetOEMUser2Activation,
3548 Privilege::Callback, ipmiOEMSetUser2Activation);
3549
3550 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3551 intel::general::cmdSetSpecialUserPassword,
3552 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303553
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003554 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003555 registerHandler(prioOemBase, intel::netFnGeneral,
3556 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3557 ipmiOEMGetProcessorErrConfig);
3558
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003559 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003560 registerHandler(prioOemBase, intel::netFnGeneral,
3561 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3562 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003563
Vernon Mauery98bbf692019-09-16 11:14:59 -07003564 ipmiPrintAndRegister(intel::netFnGeneral,
3565 intel::general::cmdSetShutdownPolicy, NULL,
3566 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003567
Vernon Mauery98bbf692019-09-16 11:14:59 -07003568 ipmiPrintAndRegister(intel::netFnGeneral,
3569 intel::general::cmdGetShutdownPolicy, NULL,
3570 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003571
anil kumar appanaf945eee2019-09-25 23:29:11 +00003572 registerHandler(prioOemBase, intel::netFnGeneral,
3573 intel::general::cmdSetFanConfig, Privilege::User,
3574 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003575
Vernon Mauery98bbf692019-09-16 11:14:59 -07003576 registerHandler(prioOemBase, intel::netFnGeneral,
3577 intel::general::cmdGetFanConfig, Privilege::User,
3578 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003579
Vernon Mauery98bbf692019-09-16 11:14:59 -07003580 registerHandler(prioOemBase, intel::netFnGeneral,
3581 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3582 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003583
Vernon Mauery98bbf692019-09-16 11:14:59 -07003584 registerHandler(prioOemBase, intel::netFnGeneral,
3585 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3586 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003587
Vernon Mauery98bbf692019-09-16 11:14:59 -07003588 registerHandler(prioOemBase, intel::netFnGeneral,
3589 intel::general::cmdSetFscParameter, Privilege::User,
3590 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003591
Vernon Mauery98bbf692019-09-16 11:14:59 -07003592 registerHandler(prioOemBase, intel::netFnGeneral,
3593 intel::general::cmdGetFscParameter, Privilege::User,
3594 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303595
Vernon Mauery98bbf692019-09-16 11:14:59 -07003596 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3597 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3598 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003599
Vernon Mauery98bbf692019-09-16 11:14:59 -07003600 registerHandler(prioOemBase, intel::netFnGeneral,
3601 intel::general::cmdGetNmiStatus, Privilege::User,
3602 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003603
Vernon Mauery98bbf692019-09-16 11:14:59 -07003604 registerHandler(prioOemBase, intel::netFnGeneral,
3605 intel::general::cmdSetNmiStatus, Privilege::Operator,
3606 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003607
Vernon Mauery98bbf692019-09-16 11:14:59 -07003608 registerHandler(prioOemBase, intel::netFnGeneral,
3609 intel::general::cmdGetEfiBootOptions, Privilege::User,
3610 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003611
Vernon Mauery98bbf692019-09-16 11:14:59 -07003612 registerHandler(prioOemBase, intel::netFnGeneral,
3613 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3614 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303615
Vernon Mauery98bbf692019-09-16 11:14:59 -07003616 registerHandler(prioOemBase, intel::netFnGeneral,
3617 intel::general::cmdGetSecurityMode, Privilege::User,
3618 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303619
Vernon Mauery98bbf692019-09-16 11:14:59 -07003620 registerHandler(prioOemBase, intel::netFnGeneral,
3621 intel::general::cmdSetSecurityMode, Privilege::Admin,
3622 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003623
Vernon Mauery98bbf692019-09-16 11:14:59 -07003624 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3625 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003626
Vernon Mauery98bbf692019-09-16 11:14:59 -07003627 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3628 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3629 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3630
3631 registerHandler(prioOemBase, intel::netFnGeneral,
3632 intel::general::cmdSetFaultIndication, Privilege::Operator,
3633 ipmiOEMSetFaultIndication);
3634
3635 registerHandler(prioOemBase, intel::netFnGeneral,
3636 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3637 ipmiOEMSetCRConfig);
3638
3639 registerHandler(prioOemBase, intel::netFnGeneral,
3640 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3641 ipmiOEMGetCRConfig);
3642
3643 registerHandler(prioOemBase, intel::netFnGeneral,
3644 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003645 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003646
Vernon Mauery98bbf692019-09-16 11:14:59 -07003647 registerHandler(prioOemBase, intel::netFnGeneral,
3648 intel::general::cmdSetDimmOffset, Privilege::Operator,
3649 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003650
Vernon Mauery98bbf692019-09-16 11:14:59 -07003651 registerHandler(prioOemBase, intel::netFnGeneral,
3652 intel::general::cmdGetDimmOffset, Privilege::Operator,
3653 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003654
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003655 registerHandler(prioOemBase, intel::netFnGeneral,
3656 intel::general::cmdGetPSUVersion, Privilege::User,
3657 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303658
3659 registerHandler(prioOemBase, intel::netFnGeneral,
3660 intel::general::cmdGetBufferSize, Privilege::User,
3661 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003662}
3663
3664} // namespace ipmi