blob: 5cf91af6440b0081b12141990b4d6c5049bf7b05 [file] [log] [blame]
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Jason M. Bills64796042018-10-03 16:51:55 -070017#include "xyz/openbmc_project/Common/error.hpp"
Kuiying Wang45f04982018-12-26 09:23:08 +080018#include "xyz/openbmc_project/Led/Physical/server.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070019
Jia, Chunhuicc49b542019-03-20 15:41:07 +080020#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080021
Chen Yugang7a04f3a2019-10-08 11:12:35 +080022#include <appcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080023#include <array>
James Feist91244a62019-02-19 15:04:54 -080024#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080025#include <boost/process/child.hpp>
26#include <boost/process/io.hpp>
Yong Li0669d192019-05-06 14:01:46 +080027#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070028#include <commandutils.hpp>
Vernon Mauery4ac799d2019-05-20 15:50:37 -070029#include <filesystem>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080030#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080031#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070032#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070033#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <phosphor-logging/log.hpp>
Chen Yugang7a04f3a2019-10-08 11:12:35 +080036#include <regex>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080037#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053038#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080039#include <string>
James Feist91244a62019-02-19 15:04:54 -080040#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080041#include <vector>
Chen Yugang97cf96e2019-11-01 08:55:11 +080042#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080043#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
44#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080045#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053046#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053047#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080048
49namespace ipmi
50{
Jason M. Bills64796042018-10-03 16:51:55 -070051static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070052
Jason M. Bills64796042018-10-03 16:51:55 -070053static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080054
Suryakanth Sekard509eb92018-11-15 17:44:11 +053055static constexpr auto ethernetIntf =
56 "xyz.openbmc_project.Network.EthernetInterface";
57static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
58static constexpr auto networkService = "xyz.openbmc_project.Network";
59static constexpr auto networkRoot = "/xyz/openbmc_project/network";
60
Chen Yugang97cf96e2019-11-01 08:55:11 +080061static constexpr const char* oemNmiSourceIntf =
62 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080063static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080064 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080065static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
66static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
67
James Feist63efafa2019-07-24 12:39:21 -070068static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
69
Chen Yugang39736d52019-07-12 16:24:33 +080070enum class NmiSource : uint8_t
71{
72 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080073 frontPanelButton = 1,
74 watchdog = 2,
75 chassisCmd = 3,
76 memoryError = 4,
77 pciBusError = 5,
78 pch = 6,
79 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080080};
81
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053082enum class SpecialUserIndex : uint8_t
83{
84 rootUser = 0,
85 atScaleDebugUser = 1
86};
87
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053088static constexpr const char* restricionModeService =
89 "xyz.openbmc_project.RestrictionMode.Manager";
90static constexpr const char* restricionModeBasePath =
91 "/xyz/openbmc_project/control/security/restriction_mode";
92static constexpr const char* restricionModeIntf =
93 "xyz.openbmc_project.Control.Security.RestrictionMode";
94static constexpr const char* restricionModeProperty = "RestrictionMode";
95
96static constexpr const char* specialModeService =
97 "xyz.openbmc_project.SpecialMode";
98static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +053099 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530100static constexpr const char* specialModeIntf =
101 "xyz.openbmc_project.Security.SpecialMode";
102static constexpr const char* specialModeProperty = "SpecialMode";
103
104static constexpr const char* dBusPropertyIntf =
105 "org.freedesktop.DBus.Properties";
106static constexpr const char* dBusPropertyGetMethod = "Get";
107static constexpr const char* dBusPropertySetMethod = "Set";
108
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800109// return code: 0 successful
110int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
111{
112 std::string objpath = "/xyz/openbmc_project/FruDevice";
113 std::string intf = "xyz.openbmc_project.FruDeviceManager";
114 std::string service = getService(bus, intf, objpath);
115 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
116 if (valueTree.empty())
117 {
118 phosphor::logging::log<phosphor::logging::level::ERR>(
119 "No object implements interface",
120 phosphor::logging::entry("INTF=%s", intf.c_str()));
121 return -1;
122 }
123
Jason M. Bills64796042018-10-03 16:51:55 -0700124 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800125 {
126 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
127 if (interface == item.second.end())
128 {
129 continue;
130 }
131
132 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
133 if (property == interface->second.end())
134 {
135 continue;
136 }
137
138 try
139 {
140 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700141 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700142 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800143 {
144 phosphor::logging::log<phosphor::logging::level::ERR>(
145 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800146 return -1;
147 }
Jason M. Bills64796042018-10-03 16:51:55 -0700148 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800149 return 0;
150 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700151 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800152 {
Jason M. Bills64796042018-10-03 16:51:55 -0700153 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154 return -1;
155 }
156 }
157 return -1;
158}
Jason M. Bills64796042018-10-03 16:51:55 -0700159
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800160ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
161 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700162 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800163{
Jason M. Bills64796042018-10-03 16:51:55 -0700164 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800165 // Status code.
166 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700167 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800168 return rc;
169}
170
171// Returns the Chassis Identifier (serial #)
172ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
173 ipmi_request_t request,
174 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700175 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800176 ipmi_context_t context)
177{
178 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700179 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800180 {
Jason M. Bills64796042018-10-03 16:51:55 -0700181 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800182 return IPMI_CC_REQ_DATA_LEN_INVALID;
183 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700184 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
185 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800186 {
Jason M. Bills64796042018-10-03 16:51:55 -0700187 *dataLen = serial.size(); // length will never exceed response length
188 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800189 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700190 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800191 return IPMI_CC_OK;
192 }
Jason M. Bills64796042018-10-03 16:51:55 -0700193 *dataLen = 0;
194 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800195}
196
197ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
198 ipmi_request_t request,
199 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700200 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800201{
202 static constexpr size_t safeBufferLength = 50;
203 char buf[safeBufferLength] = {0};
204 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
205
Jason M. Bills64796042018-10-03 16:51:55 -0700206 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800207 {
Jason M. Bills64796042018-10-03 16:51:55 -0700208 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800209 return IPMI_CC_REQ_DATA_LEN_INVALID;
210 }
211
Jason M. Bills64796042018-10-03 16:51:55 -0700212 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800213
214 snprintf(
215 buf, safeBufferLength,
216 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
217 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
218 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
219 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
220 Data->node3, Data->node2, Data->node1);
221 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
222 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800223
224 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
225 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700226 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
227 std::string service = getService(*dbus, intf, objpath);
228 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800229 return IPMI_CC_OK;
230}
231
Jason M. Billsb02bf092019-08-15 13:01:56 -0700232ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
233 uint7_t reserved1)
234{
235 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
236
237 try
238 {
239 auto service =
240 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
241 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
242 bmcResetDisablesIntf, "ResetOnSMI",
243 !disableResetOnSMI);
244 }
245 catch (std::exception& e)
246 {
247 phosphor::logging::log<phosphor::logging::level::ERR>(
248 "Failed to set BMC reset disables",
249 phosphor::logging::entry("EXCEPTION=%s", e.what()));
250 return ipmi::responseUnspecifiedError();
251 }
252
253 return ipmi::responseSuccess();
254}
255
256ipmi::RspType<bool, // disableResetOnSMI
257 uint7_t // reserved
258 >
259 ipmiOEMGetBMCResetDisables()
260{
261 bool disableResetOnSMI = true;
262
263 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
264 try
265 {
266 auto service =
267 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
268 Value variant =
269 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
270 bmcResetDisablesIntf, "ResetOnSMI");
271 disableResetOnSMI = !std::get<bool>(variant);
272 }
273 catch (std::exception& e)
274 {
275 phosphor::logging::log<phosphor::logging::level::ERR>(
276 "Failed to get BMC reset disables",
277 phosphor::logging::entry("EXCEPTION=%s", e.what()));
278 return ipmi::responseUnspecifiedError();
279 }
280
281 return ipmi::responseSuccess(disableResetOnSMI, 0);
282}
283
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800284ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
285 ipmi_request_t request, ipmi_response_t response,
286 ipmi_data_len_t dataLen, ipmi_context_t context)
287{
288 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
289
Jason M. Bills64796042018-10-03 16:51:55 -0700290 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800291 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800292 *dataLen = 0;
293 return IPMI_CC_REQ_DATA_LEN_INVALID;
294 }
Jason M. Bills64796042018-10-03 16:51:55 -0700295 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800296
Vernon Mauery15419dd2019-05-24 09:40:30 -0700297 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
298 std::string service = getService(*dbus, biosIntf, biosObjPath);
299 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800300 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
301 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700302 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800303 *dataLen = 1;
304 return IPMI_CC_OK;
305}
306
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800307bool getSwVerInfo(uint8_t& bmcMajor, uint8_t& bmcMinor, uint8_t& meMajor,
308 uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800309{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800310 // step 1 : get BMC Major and Minor numbers from its DBUS property
311 std::optional<MetaRevision> rev{};
312 try
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800313 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800314 std::string version = getActiveSoftwareVersionInfo();
315 rev = convertIntelVersion(version);
316 }
317 catch (const std::exception& e)
318 {
319 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800320 }
321
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800322 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800323 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800324 MetaRevision revision = rev.value();
325 bmcMajor = revision.major;
326
327 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
328 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
329 }
330
331 // step 2 : get ME Major and Minor numbers from its DBUS property
332 try
333 {
334 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
335 std::string service =
336 getService(*dbus, "xyz.openbmc_project.Software.Version",
337 "/xyz/openbmc_project/me_version");
338 Value variant =
339 getDbusProperty(*dbus, service, "/xyz/openbmc_project/me_version",
340 "xyz.openbmc_project.Software.Version", "Version");
341
342 std::string& meString = std::get<std::string>(variant);
343
344 // get ME major number
345 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
346 constexpr size_t matchedPhosphor = 6;
347 std::smatch results;
348 if (std::regex_match(meString, results, pattern1))
349 {
350 if (results.size() == matchedPhosphor)
351 {
352 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
353 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
354 }
355 }
356 }
357 catch (sdbusplus::exception::SdBusError& e)
358 {
359 return false;
360 }
361 return true;
362}
363
364ipmi::RspType<
365 std::variant<std::string,
366 std::tuple<uint8_t, std::array<uint8_t, 2>,
367 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
368 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
369 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
370 ipmiOEMGetDeviceInfo(uint8_t entityType, uint8_t countToRead,
371 uint8_t offset)
372{
373 if (countToRead == 0)
374 {
375 return ipmi::responseReqDataLenInvalid();
376 }
377
378 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
379 {
380 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800381 }
382
383 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800384 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800385 {
386 case OEMDevEntityType::biosId:
387 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700388 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
389 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800390 try
391 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700392 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800393 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700394 std::string& idString = std::get<std::string>(variant);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800395 if (offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800396 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800397 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800398 }
Jason M. Bills64796042018-10-03 16:51:55 -0700399 size_t length = 0;
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800400 if (countToRead > (idString.size() - offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700401 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800402 length = idString.size() - offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700403 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800404 else
405 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800406 length = countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800407 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800408
409 std::string readBuf = {0};
410 readBuf.resize(length);
411 std::copy_n(idString.begin() + offset, length,
412 (readBuf.begin()));
413 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800414 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700415 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800416 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800417 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800418 }
419 }
420 break;
421
422 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800423 {
424 constexpr const size_t verLen = 2;
425 constexpr const size_t verTotalLen = 10;
426 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
427 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
428 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
429 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
430 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
431 // data0/1: BMC version number; data6/7: ME version number
432 // the others: HSC0/1/2 version number, not avaible.
433 if (true != getSwVerInfo(bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
434 {
435 return ipmi::responseUnspecifiedError();
436 }
437 return ipmi::responseSuccess(
438 std::tuple<
439 uint8_t, std::array<uint8_t, verLen>,
440 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
441 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
442 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
443 }
444 break;
445
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800446 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800447 {
448 constexpr const size_t sdrLen = 2;
449 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
450 return ipmi::responseSuccess(
451 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
452 readBuf});
453 }
454 break;
455
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800456 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800457 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800458 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800459}
460
461ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
462 ipmi_request_t request, ipmi_response_t response,
463 ipmi_data_len_t dataLen, ipmi_context_t context)
464{
465 if (*dataLen != 0)
466 {
Jason M. Bills64796042018-10-03 16:51:55 -0700467 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800468 return IPMI_CC_REQ_DATA_LEN_INVALID;
469 }
470
471 *dataLen = 1;
472 uint8_t* res = reinterpret_cast<uint8_t*>(response);
473 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
474 // AIC is available so that BIOS will not timeout repeatly which leads to
475 // slow booting.
476 *res = 0; // Byte1=Count of SlotPosition/FruID records.
477 return IPMI_CC_OK;
478}
479
Jason M. Bills64796042018-10-03 16:51:55 -0700480ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
481 ipmi_request_t request,
482 ipmi_response_t response,
483 ipmi_data_len_t dataLen,
484 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800485{
Jason M. Bills64796042018-10-03 16:51:55 -0700486 GetPowerRestoreDelayRes* resp =
487 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
488
489 if (*dataLen != 0)
490 {
491 *dataLen = 0;
492 return IPMI_CC_REQ_DATA_LEN_INVALID;
493 }
494
Vernon Mauery15419dd2019-05-24 09:40:30 -0700495 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700496 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700497 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700498 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700499 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700500 powerRestoreDelayIntf, powerRestoreDelayProp);
501
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700502 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700503 resp->byteLSB = delay;
504 resp->byteMSB = delay >> 8;
505
506 *dataLen = sizeof(GetPowerRestoreDelayRes);
507
508 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800509}
510
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800511static uint8_t bcdToDec(uint8_t val)
512{
513 return ((val / 16 * 10) + (val % 16));
514}
515
516// Allows an update utility or system BIOS to send the status of an embedded
517// firmware update attempt to the BMC. After received, BMC will create a logging
518// record.
519ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
520 uint8_t majorRevision,
521 uint8_t minorRevision,
522 uint32_t auxInfo)
523{
524 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700525 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800526 target = (target & selEvtTargetMask) >> selEvtTargetShift;
527
528 /* make sure the status is 0, 1, or 2 as per the spec */
529 if (status > 2)
530 {
531 return ipmi::response(ipmi::ccInvalidFieldRequest);
532 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700533 /* make sure the target is 0, 1, 2, or 4 as per the spec */
534 if (target > 4 || target == 3)
535 {
536 return ipmi::response(ipmi::ccInvalidFieldRequest);
537 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800538 /*orignal OEM command is to record OEM SEL.
539 But openbmc does not support OEM SEL, so we redirect it to redfish event
540 logging. */
541 std::string buildInfo;
542 std::string action;
543 switch (FWUpdateTarget(target))
544 {
545 case FWUpdateTarget::targetBMC:
546 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700547 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800548 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
549 " BuildID: " + std::to_string(auxInfo);
550 buildInfo += std::to_string(auxInfo);
551 break;
552 case FWUpdateTarget::targetBIOS:
553 firmware = "BIOS";
554 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700555 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800556 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
557 " minor: " +
558 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
559 " ReleaseNumber: " + // ASCII encoded
560 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
561 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
562 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
563 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
564 break;
565 case FWUpdateTarget::targetME:
566 firmware = "ME";
567 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700568 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800569 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
570 " minor2: " +
571 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
572 " build1: " +
573 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
574 " build2: " +
575 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
576 break;
577 case FWUpdateTarget::targetOEMEWS:
578 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700579 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800580 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
581 " BuildID: " + std::to_string(auxInfo);
582 break;
583 }
584
Jason M. Billsdc249272019-04-03 09:58:40 -0700585 static const std::string openBMCMessageRegistryVersion("0.1");
586 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
587
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800588 switch (status)
589 {
590 case 0x0:
591 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700592 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800593 break;
594 case 0x1:
595 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700596 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800597 break;
598 case 0x2:
599 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700600 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800601 break;
602 default:
603 action = "unknown";
604 break;
605 }
606
Jason M. Billsdc249272019-04-03 09:58:40 -0700607 std::string firmwareInstanceStr =
608 firmware + " instance: " + std::to_string(instance);
609 std::string message("[firmware update] " + firmwareInstanceStr +
610 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800611
612 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700613 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
614 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
615 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800616 return ipmi::responseSuccess();
617}
618
Jason M. Bills64796042018-10-03 16:51:55 -0700619ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
620 ipmi_request_t request,
621 ipmi_response_t response,
622 ipmi_data_len_t dataLen,
623 ipmi_context_t context)
624{
625 SetPowerRestoreDelayReq* data =
626 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
627 uint16_t delay = 0;
628
629 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
630 {
631 *dataLen = 0;
632 return IPMI_CC_REQ_DATA_LEN_INVALID;
633 }
634 delay = data->byteMSB;
635 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700636 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700637 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700638 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
639 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700640 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
641 *dataLen = 0;
642
643 return IPMI_CC_OK;
644}
645
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700646static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700647{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700648 static constexpr const char* cpuPresencePathPrefix =
649 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
650 static constexpr const char* cpuPresenceIntf =
651 "xyz.openbmc_project.Inventory.Item";
652 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
653 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
654 try
Jason M. Bills64796042018-10-03 16:51:55 -0700655 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700656 auto service =
657 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
658
659 ipmi::Value result = ipmi::getDbusProperty(
660 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
661 return std::get<bool>(result);
662 }
663 catch (const std::exception& e)
664 {
665 phosphor::logging::log<phosphor::logging::level::INFO>(
666 "Cannot find processor presence",
667 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
668 return false;
669 }
670}
671
672ipmi::RspType<bool, // CATERR Reset Enabled
673 bool, // ERR2 Reset Enabled
674 uint6_t, // reserved
675 uint8_t, // reserved, returns 0x3F
676 uint6_t, // CPU1 CATERR Count
677 uint2_t, // CPU1 Status
678 uint6_t, // CPU2 CATERR Count
679 uint2_t, // CPU2 Status
680 uint6_t, // CPU3 CATERR Count
681 uint2_t, // CPU3 Status
682 uint6_t, // CPU4 CATERR Count
683 uint2_t, // CPU4 Status
684 uint8_t // Crashdump Count
685 >
686 ipmiOEMGetProcessorErrConfig()
687{
688 bool resetOnCATERR = false;
689 bool resetOnERR2 = false;
690 uint6_t cpu1CATERRCount = 0;
691 uint6_t cpu2CATERRCount = 0;
692 uint6_t cpu3CATERRCount = 0;
693 uint6_t cpu4CATERRCount = 0;
694 uint8_t crashdumpCount = 0;
695 uint2_t cpu1Status =
696 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
697 uint2_t cpu2Status =
698 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
699 uint2_t cpu3Status =
700 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
701 uint2_t cpu4Status =
702 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
703
704 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
705 try
706 {
707 auto service = ipmi::getService(*busp, processorErrConfigIntf,
708 processorErrConfigObjPath);
709
710 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
711 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
712 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
713 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
714 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
715 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
716 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
717 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
718 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
719 }
720 catch (const std::exception& e)
721 {
722 phosphor::logging::log<phosphor::logging::level::ERR>(
723 "Failed to fetch processor error config",
724 phosphor::logging::entry("ERROR=%s", e.what()));
725 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700726 }
727
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700728 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
729 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
730 cpu2Status, cpu3CATERRCount, cpu3Status,
731 cpu4CATERRCount, cpu4Status, crashdumpCount);
732}
Jason M. Bills64796042018-10-03 16:51:55 -0700733
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700734ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
735 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
736 std::optional<bool> clearCPUErrorCount,
737 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
738{
739 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700740
741 try
742 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700743 auto service = ipmi::getService(*busp, processorErrConfigIntf,
744 processorErrConfigObjPath);
745 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
746 processorErrConfigIntf, "ResetOnCATERR",
747 resetOnCATERR);
748 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
749 processorErrConfigIntf, "ResetOnERR2",
750 resetOnERR2);
751 if (clearCPUErrorCount.value_or(false))
752 {
753 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700754 processorErrConfigIntf, "ErrorCountCPU1",
755 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700756 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700757 processorErrConfigIntf, "ErrorCountCPU2",
758 static_cast<uint8_t>(0));
759 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
760 processorErrConfigIntf, "ErrorCountCPU3",
761 static_cast<uint8_t>(0));
762 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
763 processorErrConfigIntf, "ErrorCountCPU4",
764 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700765 }
766 if (clearCrashdumpCount.value_or(false))
767 {
768 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700769 processorErrConfigIntf, "CrashdumpCount",
770 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700771 }
Jason M. Bills64796042018-10-03 16:51:55 -0700772 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700773 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700774 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800775 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700776 "Failed to set processor error config",
777 phosphor::logging::entry("EXCEPTION=%s", e.what()));
778 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700779 }
780
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700781 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700782}
783
Yong Li703922d2018-11-06 13:25:31 +0800784ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
785 ipmi_request_t request,
786 ipmi_response_t response,
787 ipmi_data_len_t dataLen,
788 ipmi_context_t context)
789{
790 GetOEMShutdownPolicyRes* resp =
791 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
792
793 if (*dataLen != 0)
794 {
795 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800796 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800797 *dataLen = 0;
798 return IPMI_CC_REQ_DATA_LEN_INVALID;
799 }
800
801 *dataLen = 0;
802
803 try
804 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700805 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800806 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700807 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
808 Value variant = getDbusProperty(
809 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
810 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800811
812 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
813 convertPolicyFromString(std::get<std::string>(variant)) ==
814 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
815 NoShutdownOnOCOT)
816 {
817 resp->policy = 0;
818 }
819 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
820 convertPolicyFromString(std::get<std::string>(variant)) ==
821 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
822 Policy::ShutdownOnOCOT)
823 {
824 resp->policy = 1;
825 }
826 else
827 {
828 phosphor::logging::log<phosphor::logging::level::ERR>(
829 "oem_set_shutdown_policy: invalid property!",
830 phosphor::logging::entry(
831 "PROP=%s", std::get<std::string>(variant).c_str()));
832 return IPMI_CC_UNSPECIFIED_ERROR;
833 }
Yong Li703922d2018-11-06 13:25:31 +0800834 // TODO needs to check if it is multi-node products,
835 // policy is only supported on node 3/4
836 resp->policySupport = shutdownPolicySupported;
837 }
838 catch (sdbusplus::exception_t& e)
839 {
840 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
841 return IPMI_CC_UNSPECIFIED_ERROR;
842 }
843
844 *dataLen = sizeof(GetOEMShutdownPolicyRes);
845 return IPMI_CC_OK;
846}
847
848ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
849 ipmi_request_t request,
850 ipmi_response_t response,
851 ipmi_data_len_t dataLen,
852 ipmi_context_t context)
853{
854 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800855 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
856 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
857 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800858
859 // TODO needs to check if it is multi-node products,
860 // policy is only supported on node 3/4
861 if (*dataLen != 1)
862 {
863 phosphor::logging::log<phosphor::logging::level::ERR>(
864 "oem_set_shutdown_policy: invalid input len!");
865 *dataLen = 0;
866 return IPMI_CC_REQ_DATA_LEN_INVALID;
867 }
868
869 *dataLen = 0;
870 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
871 {
872 phosphor::logging::log<phosphor::logging::level::ERR>(
873 "oem_set_shutdown_policy: invalid input!");
874 return IPMI_CC_INVALID_FIELD_REQUEST;
875 }
876
Yong Li0669d192019-05-06 14:01:46 +0800877 if (*req == noShutdownOnOCOT)
878 {
879 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
880 Policy::NoShutdownOnOCOT;
881 }
882 else
883 {
884 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
885 Policy::ShutdownOnOCOT;
886 }
887
Yong Li703922d2018-11-06 13:25:31 +0800888 try
889 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700890 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800891 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700892 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800893 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700894 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800895 oemShutdownPolicyObjPathProp,
896 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800897 }
898 catch (sdbusplus::exception_t& e)
899 {
900 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
901 return IPMI_CC_UNSPECIFIED_ERROR;
902 }
903
904 return IPMI_CC_OK;
905}
906
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530907/** @brief implementation for check the DHCP or not in IPv4
908 * @param[in] Channel - Channel number
909 * @returns true or false.
910 */
911static bool isDHCPEnabled(uint8_t Channel)
912{
913 try
914 {
915 auto ethdevice = getChannelName(Channel);
916 if (ethdevice.empty())
917 {
918 return false;
919 }
920 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700921 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530922 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700923 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
924 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530925 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700926 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530927 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
928 {
929 return true;
930 }
931 else
932 {
933 return false;
934 }
935 }
936 catch (sdbusplus::exception_t& e)
937 {
938 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
939 return true;
940 }
941}
942
943/** @brief implementes for check the DHCP or not in IPv6
944 * @param[in] Channel - Channel number
945 * @returns true or false.
946 */
947static bool isDHCPIPv6Enabled(uint8_t Channel)
948{
949
950 try
951 {
952 auto ethdevice = getChannelName(Channel);
953 if (ethdevice.empty())
954 {
955 return false;
956 }
957 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700958 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530959 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700960 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
961 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530962 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700963 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530964 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
965 {
966 return true;
967 }
968 else
969 {
970 return false;
971 }
972 }
973 catch (sdbusplus::exception_t& e)
974 {
975 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
976 return true;
977 }
978}
979
980/** @brief implementes the creating of default new user
981 * @param[in] userName - new username in 16 bytes.
982 * @param[in] userPassword - new password in 20 bytes
983 * @returns ipmi completion code.
984 */
985ipmi::RspType<> ipmiOEMSetUser2Activation(
986 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
987 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
988{
989 bool userState = false;
990 // Check for System Interface not exist and LAN should be static
991 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
992 {
993 ChannelInfo chInfo;
994 try
995 {
996 getChannelInfo(channel, chInfo);
997 }
998 catch (sdbusplus::exception_t& e)
999 {
1000 phosphor::logging::log<phosphor::logging::level::ERR>(
1001 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1002 phosphor::logging::entry("MSG: %s", e.description()));
1003 return ipmi::response(ipmi::ccUnspecifiedError);
1004 }
1005 if (chInfo.mediumType ==
1006 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1007 {
1008 phosphor::logging::log<phosphor::logging::level::ERR>(
1009 "ipmiOEMSetUser2Activation: system interface exist .");
1010 return ipmi::response(ipmi::ccCommandNotAvailable);
1011 }
1012 else
1013 {
1014
1015 if (chInfo.mediumType ==
1016 static_cast<uint8_t>(EChannelMediumType::lan8032))
1017 {
1018 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1019 {
1020 phosphor::logging::log<phosphor::logging::level::ERR>(
1021 "ipmiOEMSetUser2Activation: DHCP enabled .");
1022 return ipmi::response(ipmi::ccCommandNotAvailable);
1023 }
1024 }
1025 }
1026 }
1027 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1028 if (ipmi::ccSuccess ==
1029 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1030 {
1031 if (enabledUsers > 1)
1032 {
1033 phosphor::logging::log<phosphor::logging::level::ERR>(
1034 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1035 return ipmi::response(ipmi::ccCommandNotAvailable);
1036 }
1037 // Check the user 2 is enabled or not
1038 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1039 if (userState == true)
1040 {
1041 phosphor::logging::log<phosphor::logging::level::ERR>(
1042 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1043 return ipmi::response(ipmi::ccCommandNotAvailable);
1044 }
1045 }
1046 else
1047 {
1048 return ipmi::response(ipmi::ccUnspecifiedError);
1049 }
1050
1051#if BYTE_ORDER == LITTLE_ENDIAN
1052 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1053#endif
1054#if BYTE_ORDER == BIG_ENDIAN
1055 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1056#endif
1057
1058 if (ipmi::ccSuccess ==
1059 ipmiUserSetUserName(ipmiDefaultUserId,
1060 reinterpret_cast<const char*>(userName.data())))
1061 {
1062 if (ipmi::ccSuccess ==
1063 ipmiUserSetUserPassword(
1064 ipmiDefaultUserId,
1065 reinterpret_cast<const char*>(userPassword.data())))
1066 {
1067 if (ipmi::ccSuccess ==
1068 ipmiUserSetPrivilegeAccess(
1069 ipmiDefaultUserId,
1070 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1071 privAccess, true))
1072 {
1073 phosphor::logging::log<phosphor::logging::level::INFO>(
1074 "ipmiOEMSetUser2Activation: user created successfully ");
1075 return ipmi::responseSuccess();
1076 }
1077 }
1078 // we need to delete the default user id which added in this command as
1079 // password / priv setting is failed.
1080 ipmiUserSetUserName(ipmiDefaultUserId, "");
1081 phosphor::logging::log<phosphor::logging::level::ERR>(
1082 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1083 }
1084 else
1085 {
1086 phosphor::logging::log<phosphor::logging::level::ERR>(
1087 "ipmiOEMSetUser2Activation: Setting username failed.");
1088 }
1089
1090 return ipmi::response(ipmi::ccCommandNotAvailable);
1091}
1092
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301093/** @brief implementes executing the linux command
1094 * @param[in] linux command
1095 * @returns status
1096 */
1097
1098static uint8_t executeCmd(const char* path)
1099{
1100 boost::process::child execProg(path);
1101 execProg.wait();
1102
1103 int retCode = execProg.exit_code();
1104 if (retCode)
1105 {
1106 return ipmi::ccUnspecifiedError;
1107 }
1108 return ipmi::ccSuccess;
1109}
1110
1111/** @brief implementes ASD Security event logging
1112 * @param[in] Event message string
1113 * @param[in] Event Severity
1114 * @returns status
1115 */
1116
1117static void atScaleDebugEventlog(std::string msg, int severity)
1118{
1119 std::string eventStr = "OpenBMC.0.1." + msg;
1120 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1121 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1122 eventStr.c_str(), NULL);
1123}
1124
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301125/** @brief implementes setting password for special user
1126 * @param[in] specialUserIndex
1127 * @param[in] userPassword - new password in 20 bytes
1128 * @returns ipmi completion code.
1129 */
1130ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1131 uint8_t specialUserIndex,
1132 std::vector<uint8_t> userPassword)
1133{
1134 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301135 ipmi_ret_t status = ipmi::ccSuccess;
1136
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301137 try
1138 {
1139 getChannelInfo(ctx->channel, chInfo);
1140 }
1141 catch (sdbusplus::exception_t& e)
1142 {
1143 phosphor::logging::log<phosphor::logging::level::ERR>(
1144 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1145 phosphor::logging::entry("MSG: %s", e.description()));
1146 return ipmi::responseUnspecifiedError();
1147 }
1148 if (chInfo.mediumType !=
1149 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1150 {
1151 phosphor::logging::log<phosphor::logging::level::ERR>(
1152 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1153 "interface");
1154 return ipmi::responseCommandNotAvailable();
1155 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301156
1157 // 0 for root user and 1 for AtScaleDebug is allowed
1158 if (specialUserIndex >
1159 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301160 {
1161 phosphor::logging::log<phosphor::logging::level::ERR>(
1162 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1163 return ipmi::responseParmOutOfRange();
1164 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301165 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301166 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301167 constexpr uint8_t minPasswordSizeRequired = 6;
1168 std::string passwd;
1169 if (userPassword.size() < minPasswordSizeRequired ||
1170 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1171 {
1172 return ipmi::responseReqDataLenInvalid();
1173 }
1174 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1175 userPassword.size());
1176 if (specialUserIndex ==
1177 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1178 {
1179 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1180
1181 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1182 }
1183 else
1184 {
1185 status = ipmiSetSpecialUserPassword("root", passwd);
1186 }
1187 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301188 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301189 else
1190 {
1191 if (specialUserIndex ==
1192 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1193 {
1194 status = executeCmd("passwd -d root");
1195 }
1196 else
1197 {
1198
1199 status = executeCmd("passwd -d asdbg");
1200
1201 if (status == 0)
1202 {
1203 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1204 LOG_INFO);
1205 }
1206 }
1207 return ipmi::response(status);
1208 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301209}
1210
Kuiying Wang45f04982018-12-26 09:23:08 +08001211namespace ledAction
1212{
1213using namespace sdbusplus::xyz::openbmc_project::Led::server;
1214std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001215 {Physical::Action::Off, 0},
1216 {Physical::Action::On, 2},
1217 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001218
1219std::map<uint8_t, std::string> offsetObjPath = {
1220 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1221
1222} // namespace ledAction
1223
1224int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1225 const std::string& objPath, uint8_t& state)
1226{
1227 try
1228 {
1229 std::string service = getService(bus, intf, objPath);
1230 Value stateValue =
1231 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001232 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001233 state = ledAction::actionDbusToIpmi.at(
1234 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1235 convertActionFromString(strState));
1236 }
1237 catch (sdbusplus::exception::SdBusError& e)
1238 {
1239 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1240 return -1;
1241 }
1242 return 0;
1243}
1244
1245ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1246 ipmi_request_t request, ipmi_response_t response,
1247 ipmi_data_len_t dataLen, ipmi_context_t context)
1248{
1249 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1250 // LED Status
1251 //[1:0] = Reserved
1252 //[3:2] = Status(Amber)
1253 //[5:4] = Status(Green)
1254 //[7:6] = System Identify
1255 // Status definitions:
1256 // 00b = Off
1257 // 01b = Blink
1258 // 10b = On
1259 // 11b = invalid
1260 if (*dataLen != 0)
1261 {
1262 phosphor::logging::log<phosphor::logging::level::ERR>(
1263 "oem_get_led_status: invalid input len!");
1264 *dataLen = 0;
1265 return IPMI_CC_REQ_DATA_LEN_INVALID;
1266 }
1267
1268 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1269 *resp = 0;
1270 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001271 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001272 for (auto it = ledAction::offsetObjPath.begin();
1273 it != ledAction::offsetObjPath.end(); ++it)
1274 {
1275 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001276 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001277 {
1278 phosphor::logging::log<phosphor::logging::level::ERR>(
1279 "oem_get_led_status: fail to get ID LED status!");
1280 return IPMI_CC_UNSPECIFIED_ERROR;
1281 }
1282 *resp |= state << it->first;
1283 }
1284
1285 *dataLen = sizeof(*resp);
1286 return IPMI_CC_OK;
1287}
1288
Yong Li23737fe2019-02-19 08:49:55 +08001289ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1290 ipmi_request_t request,
1291 ipmi_response_t response,
1292 ipmi_data_len_t dataLen,
1293 ipmi_context_t context)
1294{
1295 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1296 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1297
1298 if (*dataLen == 0)
1299 {
1300 phosphor::logging::log<phosphor::logging::level::ERR>(
1301 "CfgHostSerial: invalid input len!",
1302 phosphor::logging::entry("LEN=%d", *dataLen));
1303 return IPMI_CC_REQ_DATA_LEN_INVALID;
1304 }
1305
1306 switch (req->command)
1307 {
1308 case getHostSerialCfgCmd:
1309 {
1310 if (*dataLen != 1)
1311 {
1312 phosphor::logging::log<phosphor::logging::level::ERR>(
1313 "CfgHostSerial: invalid input len!");
1314 *dataLen = 0;
1315 return IPMI_CC_REQ_DATA_LEN_INVALID;
1316 }
1317
1318 *dataLen = 0;
1319
1320 boost::process::ipstream is;
1321 std::vector<std::string> data;
1322 std::string line;
1323 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1324 boost::process::std_out > is);
1325
1326 while (c1.running() && std::getline(is, line) && !line.empty())
1327 {
1328 data.push_back(line);
1329 }
1330
1331 c1.wait();
1332 if (c1.exit_code())
1333 {
1334 phosphor::logging::log<phosphor::logging::level::ERR>(
1335 "CfgHostSerial:: error on execute",
1336 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1337 // Using the default value
1338 *resp = 0;
1339 }
1340 else
1341 {
1342 if (data.size() != 1)
1343 {
1344 phosphor::logging::log<phosphor::logging::level::ERR>(
1345 "CfgHostSerial:: error on read env");
1346 return IPMI_CC_UNSPECIFIED_ERROR;
1347 }
1348 try
1349 {
1350 unsigned long tmp = std::stoul(data[0]);
1351 if (tmp > std::numeric_limits<uint8_t>::max())
1352 {
1353 throw std::out_of_range("Out of range");
1354 }
1355 *resp = static_cast<uint8_t>(tmp);
1356 }
1357 catch (const std::invalid_argument& e)
1358 {
1359 phosphor::logging::log<phosphor::logging::level::ERR>(
1360 "invalid config ",
1361 phosphor::logging::entry("ERR=%s", e.what()));
1362 return IPMI_CC_UNSPECIFIED_ERROR;
1363 }
1364 catch (const std::out_of_range& e)
1365 {
1366 phosphor::logging::log<phosphor::logging::level::ERR>(
1367 "out_of_range config ",
1368 phosphor::logging::entry("ERR=%s", e.what()));
1369 return IPMI_CC_UNSPECIFIED_ERROR;
1370 }
1371 }
1372
1373 *dataLen = 1;
1374 break;
1375 }
1376 case setHostSerialCfgCmd:
1377 {
1378 if (*dataLen != sizeof(CfgHostSerialReq))
1379 {
1380 phosphor::logging::log<phosphor::logging::level::ERR>(
1381 "CfgHostSerial: invalid input len!");
1382 *dataLen = 0;
1383 return IPMI_CC_REQ_DATA_LEN_INVALID;
1384 }
1385
1386 *dataLen = 0;
1387
1388 if (req->parameter > HostSerialCfgParamMax)
1389 {
1390 phosphor::logging::log<phosphor::logging::level::ERR>(
1391 "CfgHostSerial: invalid input!");
1392 return IPMI_CC_INVALID_FIELD_REQUEST;
1393 }
1394
1395 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1396 std::to_string(req->parameter));
1397
1398 c1.wait();
1399 if (c1.exit_code())
1400 {
1401 phosphor::logging::log<phosphor::logging::level::ERR>(
1402 "CfgHostSerial:: error on execute",
1403 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1404 return IPMI_CC_UNSPECIFIED_ERROR;
1405 }
1406 break;
1407 }
1408 default:
1409 phosphor::logging::log<phosphor::logging::level::ERR>(
1410 "CfgHostSerial: invalid input!");
1411 *dataLen = 0;
1412 return IPMI_CC_INVALID_FIELD_REQUEST;
1413 }
1414
1415 return IPMI_CC_OK;
1416}
1417
James Feist91244a62019-02-19 15:04:54 -08001418constexpr const char* thermalModeInterface =
1419 "xyz.openbmc_project.Control.ThermalMode";
1420constexpr const char* thermalModePath =
1421 "/xyz/openbmc_project/control/thermal_mode";
1422
1423bool getFanProfileInterface(
1424 sdbusplus::bus::bus& bus,
1425 boost::container::flat_map<
1426 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1427{
1428 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1429 "GetAll");
1430 call.append(thermalModeInterface);
1431 try
1432 {
1433 auto data = bus.call(call);
1434 data.read(resp);
1435 }
1436 catch (sdbusplus::exception_t& e)
1437 {
1438 phosphor::logging::log<phosphor::logging::level::ERR>(
1439 "getFanProfileInterface: can't get thermal mode!",
1440 phosphor::logging::entry("ERR=%s", e.what()));
1441 return false;
1442 }
1443 return true;
1444}
1445
anil kumar appanaf945eee2019-09-25 23:29:11 +00001446/**@brief implements the OEM set fan config.
1447 * @param selectedFanProfile - fan profile to enable
1448 * @param reserved1
1449 * @param performanceMode - Performance/Acoustic mode
1450 * @param reserved2
1451 * @param setPerformanceMode - set Performance/Acoustic mode
1452 * @param setFanProfile - set fan profile
1453 *
1454 * @return IPMI completion code.
1455 **/
1456ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1457
1458 uint2_t reserved1, bool performanceMode,
1459 uint3_t reserved2, bool setPerformanceMode,
1460 bool setFanProfile)
James Feist91244a62019-02-19 15:04:54 -08001461{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001462 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001463 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001464 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001465 }
James Feist91244a62019-02-19 15:04:54 -08001466 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001467 boost::container::flat_map<
1468 std::string, std::variant<std::vector<std::string>, std::string>>
1469 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001470 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1471 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001472 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001473 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001474 }
1475
1476 std::vector<std::string>* supported =
1477 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1478 if (supported == nullptr)
1479 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001480 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001481 }
1482 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001483 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001484 {
James Feist91244a62019-02-19 15:04:54 -08001485 if (performanceMode)
1486 {
1487
1488 if (std::find(supported->begin(), supported->end(),
1489 "Performance") != supported->end())
1490 {
1491 mode = "Performance";
1492 }
1493 }
1494 else
1495 {
James Feist91244a62019-02-19 15:04:54 -08001496 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1497 supported->end())
1498 {
1499 mode = "Acoustic";
1500 }
1501 }
1502 if (mode.empty())
1503 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001504 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001505 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001506
1507 try
1508 {
1509 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1510 thermalModeInterface, "Current", mode);
1511 }
1512 catch (sdbusplus::exception_t& e)
1513 {
1514 phosphor::logging::log<phosphor::logging::level::ERR>(
1515 "ipmiOEMSetFanConfig: can't set thermal mode!",
1516 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1517 return ipmi::responseResponseError();
1518 }
James Feist91244a62019-02-19 15:04:54 -08001519 }
1520
anil kumar appanaf945eee2019-09-25 23:29:11 +00001521 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001522}
1523
James Feist5b693632019-07-09 09:06:09 -07001524ipmi::RspType<uint8_t, // profile support map
1525 uint8_t, // fan control profile enable
1526 uint8_t, // flags
1527 uint32_t // dimm presence bit map
1528 >
1529 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001530{
James Feist91244a62019-02-19 15:04:54 -08001531 boost::container::flat_map<
1532 std::string, std::variant<std::vector<std::string>, std::string>>
1533 profileData;
1534
Vernon Mauery15419dd2019-05-24 09:40:30 -07001535 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1536 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001537 {
James Feist5b693632019-07-09 09:06:09 -07001538 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001539 }
1540
1541 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1542
1543 if (current == nullptr)
1544 {
1545 phosphor::logging::log<phosphor::logging::level::ERR>(
1546 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001547 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001548 }
1549 bool performance = (*current == "Performance");
1550
James Feist5b693632019-07-09 09:06:09 -07001551 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001552 if (performance)
1553 {
James Feist5b693632019-07-09 09:06:09 -07001554 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001555 }
1556
James Feist5b693632019-07-09 09:06:09 -07001557 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001558}
James Feist5f957ca2019-03-14 15:33:55 -07001559constexpr const char* cfmLimitSettingPath =
1560 "/xyz/openbmc_project/control/cfm_limit";
1561constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001562constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001563constexpr const size_t legacyPCHSensorNumber = 0x22;
1564constexpr const char* exitAirPathName = "Exit_Air";
1565constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001566constexpr const char* pidConfigurationIface =
1567 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001568
James Feist09f6b602019-08-08 11:30:03 -07001569static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001570{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001571 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001572 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001573 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1574 "/xyz/openbmc_project/object_mapper",
1575 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001576
James Feistacc8a4e2019-04-02 14:23:57 -07001577 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001578 std::string path;
1579 GetSubTreeType resp;
1580 try
1581 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001582 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001583 reply.read(resp);
1584 }
1585 catch (sdbusplus::exception_t&)
1586 {
1587 phosphor::logging::log<phosphor::logging::level::ERR>(
1588 "ipmiOEMGetFscParameter: mapper error");
1589 };
James Feist09f6b602019-08-08 11:30:03 -07001590 auto config =
1591 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1592 return pair.first.find(name) != std::string::npos;
1593 });
James Feistfaa4f222019-03-21 16:21:55 -07001594 if (config != resp.end())
1595 {
1596 path = std::move(config->first);
1597 }
1598 return path;
1599}
James Feist5f957ca2019-03-14 15:33:55 -07001600
James Feistacc8a4e2019-04-02 14:23:57 -07001601// flat map to make alphabetical
1602static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1603{
1604 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001605 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001606 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001607 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1608 "/xyz/openbmc_project/object_mapper",
1609 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001610
1611 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1612 GetSubTreeType resp;
1613
1614 try
1615 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001616 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001617 reply.read(resp);
1618 }
1619 catch (sdbusplus::exception_t&)
1620 {
1621 phosphor::logging::log<phosphor::logging::level::ERR>(
1622 "getFanConfigPaths: mapper error");
1623 };
1624 for (const auto& [path, objects] : resp)
1625 {
1626 if (objects.empty())
1627 {
1628 continue; // should be impossible
1629 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001630
1631 try
1632 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001633 ret.emplace(path,
1634 getAllDbusProperties(*dbus, objects[0].first, path,
1635 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001636 }
1637 catch (sdbusplus::exception_t& e)
1638 {
1639 phosphor::logging::log<phosphor::logging::level::ERR>(
1640 "getPidConfigs: can't get DbusProperties!",
1641 phosphor::logging::entry("ERR=%s", e.what()));
1642 }
James Feistacc8a4e2019-04-02 14:23:57 -07001643 }
1644 return ret;
1645}
1646
1647ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1648{
1649 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1650 if (data.empty())
1651 {
1652 return ipmi::responseResponseError();
1653 }
1654 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1655 for (const auto& [_, pid] : data)
1656 {
1657 auto findClass = pid.find("Class");
1658 if (findClass == pid.end())
1659 {
1660 phosphor::logging::log<phosphor::logging::level::ERR>(
1661 "ipmiOEMGetFscParameter: found illegal pid "
1662 "configurations");
1663 return ipmi::responseResponseError();
1664 }
1665 std::string type = std::get<std::string>(findClass->second);
1666 if (type == "fan")
1667 {
1668 auto findOutLimit = pid.find("OutLimitMin");
1669 if (findOutLimit == pid.end())
1670 {
1671 phosphor::logging::log<phosphor::logging::level::ERR>(
1672 "ipmiOEMGetFscParameter: found illegal pid "
1673 "configurations");
1674 return ipmi::responseResponseError();
1675 }
1676 // get the min out of all the offsets
1677 minOffset = std::min(
1678 minOffset,
1679 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1680 }
1681 }
1682 if (minOffset == std::numeric_limits<uint8_t>::max())
1683 {
1684 phosphor::logging::log<phosphor::logging::level::ERR>(
1685 "ipmiOEMGetFscParameter: found no fan configurations!");
1686 return ipmi::responseResponseError();
1687 }
1688
1689 return ipmi::responseSuccess(minOffset);
1690}
1691
1692ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1693{
1694 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1695 if (data.empty())
1696 {
1697
1698 phosphor::logging::log<phosphor::logging::level::ERR>(
1699 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1700 return ipmi::responseResponseError();
1701 }
1702
Vernon Mauery15419dd2019-05-24 09:40:30 -07001703 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001704 bool found = false;
1705 for (const auto& [path, pid] : data)
1706 {
1707 auto findClass = pid.find("Class");
1708 if (findClass == pid.end())
1709 {
1710
1711 phosphor::logging::log<phosphor::logging::level::ERR>(
1712 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1713 "configurations");
1714 return ipmi::responseResponseError();
1715 }
1716 std::string type = std::get<std::string>(findClass->second);
1717 if (type == "fan")
1718 {
1719 auto findOutLimit = pid.find("OutLimitMin");
1720 if (findOutLimit == pid.end())
1721 {
1722
1723 phosphor::logging::log<phosphor::logging::level::ERR>(
1724 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1725 "configurations");
1726 return ipmi::responseResponseError();
1727 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001728 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001729 path, pidConfigurationIface, "OutLimitMin",
1730 static_cast<double>(offset));
1731 found = true;
1732 }
1733 }
1734 if (!found)
1735 {
1736 phosphor::logging::log<phosphor::logging::level::ERR>(
1737 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1738 return ipmi::responseResponseError();
1739 }
1740
1741 return ipmi::responseSuccess();
1742}
1743
1744ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1745 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001746{
1747 constexpr const size_t disableLimiting = 0x0;
1748
Vernon Mauery15419dd2019-05-24 09:40:30 -07001749 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001750 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001751 {
James Feist09f6b602019-08-08 11:30:03 -07001752 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001753 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001754 {
James Feist09f6b602019-08-08 11:30:03 -07001755 pathName = exitAirPathName;
1756 }
1757 else if (param1 == legacyPCHSensorNumber)
1758 {
1759 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001760 }
1761 else
1762 {
James Feistacc8a4e2019-04-02 14:23:57 -07001763 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001764 }
James Feist09f6b602019-08-08 11:30:03 -07001765 std::string path = getConfigPath(pathName);
1766 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1767 pidConfigurationIface, "SetPoint",
1768 static_cast<double>(param2));
1769 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001770 }
James Feistacc8a4e2019-04-02 14:23:57 -07001771 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001772 {
James Feistacc8a4e2019-04-02 14:23:57 -07001773 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001774
1775 // must be greater than 50 based on eps
1776 if (cfm < 50 && cfm != disableLimiting)
1777 {
James Feistacc8a4e2019-04-02 14:23:57 -07001778 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001779 }
1780
1781 try
1782 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001783 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001784 cfmLimitIface, "Limit",
1785 static_cast<double>(cfm));
1786 }
1787 catch (sdbusplus::exception_t& e)
1788 {
1789 phosphor::logging::log<phosphor::logging::level::ERR>(
1790 "ipmiOEMSetFscParameter: can't set cfm setting!",
1791 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001792 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001793 }
James Feistacc8a4e2019-04-02 14:23:57 -07001794 return ipmi::responseSuccess();
1795 }
1796 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1797 {
1798 constexpr const size_t maxDomainCount = 8;
1799 uint8_t requestedDomainMask = param1;
1800 boost::container::flat_map data = getPidConfigs();
1801 if (data.empty())
1802 {
1803
1804 phosphor::logging::log<phosphor::logging::level::ERR>(
1805 "ipmiOEMSetFscParameter: found no pid configurations!");
1806 return ipmi::responseResponseError();
1807 }
1808 size_t count = 0;
1809 for (const auto& [path, pid] : data)
1810 {
1811 auto findClass = pid.find("Class");
1812 if (findClass == pid.end())
1813 {
1814
1815 phosphor::logging::log<phosphor::logging::level::ERR>(
1816 "ipmiOEMSetFscParameter: found illegal pid "
1817 "configurations");
1818 return ipmi::responseResponseError();
1819 }
1820 std::string type = std::get<std::string>(findClass->second);
1821 if (type == "fan")
1822 {
1823 if (requestedDomainMask & (1 << count))
1824 {
1825 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001826 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001827 pidConfigurationIface, "OutLimitMax",
1828 static_cast<double>(param2));
1829 }
1830 count++;
1831 }
1832 }
1833 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001834 }
1835 else
1836 {
1837 // todo other command parts possibly
1838 // tcontrol is handled in peci now
1839 // fan speed offset not implemented yet
1840 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001841 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001842 }
1843}
1844
James Feistacc8a4e2019-04-02 14:23:57 -07001845ipmi::RspType<
1846 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1847 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001848{
James Feist09f6b602019-08-08 11:30:03 -07001849 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001850
Vernon Mauery15419dd2019-05-24 09:40:30 -07001851 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001852 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001853 {
James Feistacc8a4e2019-04-02 14:23:57 -07001854 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001855 {
James Feistacc8a4e2019-04-02 14:23:57 -07001856 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001857 }
1858
James Feist09f6b602019-08-08 11:30:03 -07001859 std::string pathName;
1860
1861 if (*param == legacyExitAirSensorNumber)
1862 {
1863 pathName = exitAirPathName;
1864 }
1865 else if (*param == legacyPCHSensorNumber)
1866 {
1867 pathName = pchPathName;
1868 }
1869 else
James Feistfaa4f222019-03-21 16:21:55 -07001870 {
James Feistacc8a4e2019-04-02 14:23:57 -07001871 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001872 }
James Feist09f6b602019-08-08 11:30:03 -07001873
1874 uint8_t setpoint = legacyDefaultSetpoint;
1875 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001876 if (path.size())
1877 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001878 Value val = ipmi::getDbusProperty(
1879 *dbus, "xyz.openbmc_project.EntityManager", path,
1880 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001881 setpoint = std::floor(std::get<double>(val) + 0.5);
1882 }
1883
1884 // old implementation used to return the "default" and current, we
1885 // don't make the default readily available so just make both the
1886 // same
James Feistfaa4f222019-03-21 16:21:55 -07001887
James Feistacc8a4e2019-04-02 14:23:57 -07001888 return ipmi::responseSuccess(
1889 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001890 }
James Feistacc8a4e2019-04-02 14:23:57 -07001891 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1892 {
1893 constexpr const size_t maxDomainCount = 8;
1894
1895 if (!param)
1896 {
1897 return ipmi::responseReqDataLenInvalid();
1898 }
1899 uint8_t requestedDomain = *param;
1900 if (requestedDomain >= maxDomainCount)
1901 {
1902 return ipmi::responseInvalidFieldRequest();
1903 }
1904
1905 boost::container::flat_map data = getPidConfigs();
1906 if (data.empty())
1907 {
1908 phosphor::logging::log<phosphor::logging::level::ERR>(
1909 "ipmiOEMGetFscParameter: found no pid configurations!");
1910 return ipmi::responseResponseError();
1911 }
1912 size_t count = 0;
1913 for (const auto& [_, pid] : data)
1914 {
1915 auto findClass = pid.find("Class");
1916 if (findClass == pid.end())
1917 {
1918 phosphor::logging::log<phosphor::logging::level::ERR>(
1919 "ipmiOEMGetFscParameter: found illegal pid "
1920 "configurations");
1921 return ipmi::responseResponseError();
1922 }
1923 std::string type = std::get<std::string>(findClass->second);
1924 if (type == "fan")
1925 {
1926 if (requestedDomain == count)
1927 {
1928 auto findOutLimit = pid.find("OutLimitMax");
1929 if (findOutLimit == pid.end())
1930 {
1931 phosphor::logging::log<phosphor::logging::level::ERR>(
1932 "ipmiOEMGetFscParameter: found illegal pid "
1933 "configurations");
1934 return ipmi::responseResponseError();
1935 }
1936
1937 return ipmi::responseSuccess(
1938 static_cast<uint8_t>(std::floor(
1939 std::get<double>(findOutLimit->second) + 0.5)));
1940 }
1941 else
1942 {
1943 count++;
1944 }
1945 }
1946 }
1947
1948 return ipmi::responseInvalidFieldRequest();
1949 }
1950 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001951 {
1952
1953 /*
1954 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001955 previous behavior didn't seem to prevent this, ignore the check for
1956 now.
James Feist5f957ca2019-03-14 15:33:55 -07001957
James Feistacc8a4e2019-04-02 14:23:57 -07001958 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001959 {
1960 phosphor::logging::log<phosphor::logging::level::ERR>(
1961 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001962 return IPMI_CC_REQ_DATA_LEN_INVALID;
1963 }
1964 */
1965 Value cfmLimit;
1966 Value cfmMaximum;
1967 try
1968 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001969 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001970 cfmLimitSettingPath, cfmLimitIface,
1971 "Limit");
1972 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001973 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001974 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1975 }
1976 catch (sdbusplus::exception_t& e)
1977 {
1978 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001979 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001980 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001981 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001982 }
1983
James Feistacc8a4e2019-04-02 14:23:57 -07001984 double cfmMax = std::get<double>(cfmMaximum);
1985 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001986
James Feistacc8a4e2019-04-02 14:23:57 -07001987 cfmLim = std::floor(cfmLim + 0.5);
1988 cfmMax = std::floor(cfmMax + 0.5);
1989 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1990 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001991
James Feistacc8a4e2019-04-02 14:23:57 -07001992 return ipmi::responseSuccess(
1993 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001994 }
James Feistacc8a4e2019-04-02 14:23:57 -07001995
James Feist5f957ca2019-03-14 15:33:55 -07001996 else
1997 {
1998 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001999 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002000 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002001 }
2002}
2003
Cheng C Yang773703a2019-08-15 09:41:11 +08002004using crConfigVariant =
2005 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2006
2007int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2008 const crConfigVariant& value,
2009 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2010{
2011 boost::system::error_code ec;
2012 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002013 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002014 "/xyz/openbmc_project/control/power_supply_redundancy",
2015 "org.freedesktop.DBus.Properties", "Set",
2016 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2017 if (ec)
2018 {
2019 phosphor::logging::log<phosphor::logging::level::ERR>(
2020 "Failed to set dbus property to cold redundancy");
2021 return -1;
2022 }
2023
2024 return 0;
2025}
2026
2027int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2028 crConfigVariant& value,
2029 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2030{
2031 boost::system::error_code ec;
2032 value = ctx->bus->yield_method_call<crConfigVariant>(
James Feist28c72902019-09-16 10:34:07 -07002033 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002034 "/xyz/openbmc_project/control/power_supply_redundancy",
2035 "org.freedesktop.DBus.Properties", "Get",
2036 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2037 if (ec)
2038 {
2039 phosphor::logging::log<phosphor::logging::level::ERR>(
2040 "Failed to get dbus property to cold redundancy");
2041 return -1;
2042 }
2043 return 0;
2044}
2045
2046uint8_t getPSUCount(void)
2047{
2048 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2049 ipmi::Value num;
2050 try
2051 {
2052 num = ipmi::getDbusProperty(
2053 *dbus, "xyz.openbmc_project.PSURedundancy",
2054 "/xyz/openbmc_project/control/power_supply_redundancy",
2055 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2056 }
2057 catch (sdbusplus::exception_t& e)
2058 {
2059 phosphor::logging::log<phosphor::logging::level::ERR>(
2060 "Failed to get PSUNumber property from dbus interface");
2061 return 0;
2062 }
2063 uint8_t* pNum = std::get_if<uint8_t>(&num);
2064 if (!pNum)
2065 {
2066 phosphor::logging::log<phosphor::logging::level::ERR>(
2067 "Error to get PSU Number");
2068 return 0;
2069 }
2070 return *pNum;
2071}
2072
2073bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2074{
2075 if (conf.size() < num)
2076 {
2077 phosphor::logging::log<phosphor::logging::level::ERR>(
2078 "Invalid PSU Ranking");
2079 return false;
2080 }
2081 std::set<uint8_t> confSet;
2082 for (uint8_t i = 0; i < num; i++)
2083 {
2084 if (conf[i] > num)
2085 {
2086 phosphor::logging::log<phosphor::logging::level::ERR>(
2087 "PSU Ranking is larger than current PSU number");
2088 return false;
2089 }
2090 confSet.emplace(conf[i]);
2091 }
2092
2093 if (confSet.size() != num)
2094 {
2095 phosphor::logging::log<phosphor::logging::level::ERR>(
2096 "duplicate PSU Ranking");
2097 return false;
2098 }
2099 return true;
2100}
2101
2102enum class crParameter
2103{
2104 crStatus = 0,
2105 crFeature = 1,
2106 rotationFeature = 2,
2107 rotationAlgo = 3,
2108 rotationPeriod = 4,
2109 numOfPSU = 5
2110};
2111
2112constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2113static const constexpr uint32_t oneDay = 0x15180;
2114static const constexpr uint32_t oneMonth = 0xf53700;
2115static const constexpr uint8_t userSpecific = 0x01;
2116static const constexpr uint8_t crSetCompleted = 0;
2117ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2118 uint8_t parameter,
2119 ipmi::message::Payload& payload)
2120{
2121 switch (static_cast<crParameter>(parameter))
2122 {
2123 case crParameter::crFeature:
2124 {
2125 uint8_t param1;
2126 if (payload.unpack(param1) || !payload.fullyUnpacked())
2127 {
2128 return ipmi::responseReqDataLenInvalid();
2129 }
2130 // ColdRedundancy Enable can only be true or flase
2131 if (param1 > 1)
2132 {
2133 return ipmi::responseInvalidFieldRequest();
2134 }
2135 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2136 static_cast<bool>(param1)))
2137 {
2138 return ipmi::responseResponseError();
2139 }
2140 break;
2141 }
2142 case crParameter::rotationFeature:
2143 {
2144 uint8_t param1;
2145 if (payload.unpack(param1) || !payload.fullyUnpacked())
2146 {
2147 return ipmi::responseReqDataLenInvalid();
2148 }
2149 // Rotation Enable can only be true or false
2150 if (param1 > 1)
2151 {
2152 return ipmi::responseInvalidFieldRequest();
2153 }
2154 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2155 {
2156 return ipmi::responseResponseError();
2157 }
2158 break;
2159 }
2160 case crParameter::rotationAlgo:
2161 {
2162 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2163 std::string algoName;
2164 uint8_t param1;
2165 if (payload.unpack(param1))
2166 {
2167 return ipmi::responseReqDataLenInvalid();
2168 }
2169 switch (param1)
2170 {
2171 case 0:
2172 algoName = "xyz.openbmc_project.Control."
2173 "PowerSupplyRedundancy.Algo.bmcSpecific";
2174 break;
2175 case 1:
2176 algoName = "xyz.openbmc_project.Control."
2177 "PowerSupplyRedundancy.Algo.userSpecific";
2178 break;
2179 default:
2180 return ipmi::responseInvalidFieldRequest();
2181 }
2182 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2183 {
2184 return ipmi::responseResponseError();
2185 }
2186
2187 uint8_t numberOfPSU = getPSUCount();
2188 if (!numberOfPSU)
2189 {
2190 return ipmi::responseResponseError();
2191 }
2192 std::vector<uint8_t> rankOrder;
2193
2194 if (param1 == userSpecific)
2195 {
2196 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2197 {
2198 ipmi::responseReqDataLenInvalid();
2199 }
Yong Li83315132019-10-23 17:42:24 +08002200 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002201 {
2202 return ipmi::responseReqDataLenInvalid();
2203 }
2204
2205 if (!validateCRAlgo(rankOrder, numberOfPSU))
2206 {
2207 return ipmi::responseInvalidFieldRequest();
2208 }
2209 }
2210 else
2211 {
2212 if (rankOrder.size() > 0)
2213 {
2214 return ipmi::responseReqDataLenInvalid();
2215 }
2216 for (uint8_t i = 1; i <= numberOfPSU; i++)
2217 {
2218 rankOrder.emplace_back(i);
2219 }
2220 }
2221 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2222 {
2223 return ipmi::responseResponseError();
2224 }
2225 break;
2226 }
2227 case crParameter::rotationPeriod:
2228 {
2229 // Minimum Rotation period is One day (86400 seconds) and Max
2230 // Rotation Period is 6 month (0xf53700 seconds)
2231 uint32_t period;
2232 if (payload.unpack(period) || !payload.fullyUnpacked())
2233 {
2234 return ipmi::responseReqDataLenInvalid();
2235 }
2236 if ((period < oneDay) || (period > oneMonth))
2237 {
2238 return ipmi::responseInvalidFieldRequest();
2239 }
2240 if (setCRConfig(ctx, "PeriodOfRotation", period))
2241 {
2242 return ipmi::responseResponseError();
2243 }
2244 break;
2245 }
2246 default:
2247 {
2248 return ipmi::response(ccParameterNotSupported);
2249 }
2250 }
2251
2252 // TODO Halfwidth needs to set SetInProgress
2253 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002254 std::string("xyz.openbmc_project.Control."
2255 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002256 {
2257 return ipmi::responseResponseError();
2258 }
2259 return ipmi::responseSuccess(crSetCompleted);
2260}
2261
Yong Li83315132019-10-23 17:42:24 +08002262ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002263 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2264{
2265 crConfigVariant value;
2266 switch (static_cast<crParameter>(parameter))
2267 {
2268 case crParameter::crStatus:
2269 {
2270 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2271 {
2272 return ipmi::responseResponseError();
2273 }
2274 std::string* pStatus = std::get_if<std::string>(&value);
2275 if (!pStatus)
2276 {
2277 phosphor::logging::log<phosphor::logging::level::ERR>(
2278 "Error to get ColdRedundancyStatus property");
2279 return ipmi::responseResponseError();
2280 }
2281 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2282 auto status =
2283 server::PowerSupplyRedundancy::convertStatusFromString(
2284 *pStatus);
2285 switch (status)
2286 {
2287 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002288 return ipmi::responseSuccess(parameter,
2289 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002290
2291 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002292 return ipmi::responseSuccess(parameter,
2293 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002294 default:
2295 phosphor::logging::log<phosphor::logging::level::ERR>(
2296 "Error to get valid status");
2297 return ipmi::responseResponseError();
2298 }
2299 }
2300 case crParameter::crFeature:
2301 {
2302 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2303 {
2304 return ipmi::responseResponseError();
2305 }
2306 bool* pResponse = std::get_if<bool>(&value);
2307 if (!pResponse)
2308 {
2309 phosphor::logging::log<phosphor::logging::level::ERR>(
2310 "Error to get ColdRedundancyEnable property");
2311 return ipmi::responseResponseError();
2312 }
2313
Cheng C Yangf41e3342019-09-10 04:47:23 +08002314 return ipmi::responseSuccess(parameter,
2315 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002316 }
2317 case crParameter::rotationFeature:
2318 {
2319 if (getCRConfig(ctx, "RotationEnabled", value))
2320 {
2321 return ipmi::responseResponseError();
2322 }
2323 bool* pResponse = std::get_if<bool>(&value);
2324 if (!pResponse)
2325 {
2326 phosphor::logging::log<phosphor::logging::level::ERR>(
2327 "Error to get RotationEnabled property");
2328 return ipmi::responseResponseError();
2329 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002330 return ipmi::responseSuccess(parameter,
2331 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002332 }
2333 case crParameter::rotationAlgo:
2334 {
2335 if (getCRConfig(ctx, "RotationAlgorithm", value))
2336 {
2337 return ipmi::responseResponseError();
2338 }
2339
2340 std::string* pAlgo = std::get_if<std::string>(&value);
2341 if (!pAlgo)
2342 {
2343 phosphor::logging::log<phosphor::logging::level::ERR>(
2344 "Error to get RotationAlgorithm property");
2345 return ipmi::responseResponseError();
2346 }
Yong Li83315132019-10-23 17:42:24 +08002347 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002348 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2349 auto algo =
2350 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002351
Cheng C Yang773703a2019-08-15 09:41:11 +08002352 switch (algo)
2353 {
2354 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002355 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002356 break;
2357 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002358 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002359 break;
2360 default:
2361 phosphor::logging::log<phosphor::logging::level::ERR>(
2362 "Error to get valid algo");
2363 return ipmi::responseResponseError();
2364 }
2365
2366 if (getCRConfig(ctx, "RotationRankOrder", value))
2367 {
2368 return ipmi::responseResponseError();
2369 }
2370 std::vector<uint8_t>* pResponse =
2371 std::get_if<std::vector<uint8_t>>(&value);
2372 if (!pResponse)
2373 {
2374 phosphor::logging::log<phosphor::logging::level::ERR>(
2375 "Error to get RotationRankOrder property");
2376 return ipmi::responseResponseError();
2377 }
Yong Li83315132019-10-23 17:42:24 +08002378
Cheng C Yang773703a2019-08-15 09:41:11 +08002379 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002380 std::back_inserter(response));
2381
Cheng C Yangf41e3342019-09-10 04:47:23 +08002382 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002383 }
2384 case crParameter::rotationPeriod:
2385 {
2386 if (getCRConfig(ctx, "PeriodOfRotation", value))
2387 {
2388 return ipmi::responseResponseError();
2389 }
2390 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2391 if (!pResponse)
2392 {
2393 phosphor::logging::log<phosphor::logging::level::ERR>(
2394 "Error to get RotationAlgorithm property");
2395 return ipmi::responseResponseError();
2396 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002397 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002398 }
2399 case crParameter::numOfPSU:
2400 {
2401 uint8_t numberOfPSU = getPSUCount();
2402 if (!numberOfPSU)
2403 {
2404 return ipmi::responseResponseError();
2405 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002406 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002407 }
2408 default:
2409 {
2410 return ipmi::response(ccParameterNotSupported);
2411 }
2412 }
2413}
2414
Zhu, Yungebe560b02019-04-21 21:19:21 -04002415ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2416 uint8_t faultState,
2417 uint8_t faultGroup,
2418 std::array<uint8_t, 8>& ledStateData)
2419{
2420 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2421 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2422 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2423 static const std::array<std::string, maxFaultType> faultNames = {
2424 "faultFan", "faultTemp", "faultPower",
2425 "faultDriveSlot", "faultSoftware", "faultMemory"};
2426 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2427 static constexpr const char* postfixValue = "/value";
2428
2429 constexpr uint8_t maxFaultSource = 0x4;
2430 constexpr uint8_t skipLEDs = 0xFF;
2431 constexpr uint8_t pinSize = 64;
2432 constexpr uint8_t groupSize = 16;
2433
2434 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2435 uint64_t resFIndex = 0;
2436 std::string resFType;
2437 std::string service;
2438 ObjectValueTree valueTree;
2439
2440 // Validate the source, fault type
2441 if ((sourceId >= maxFaultSource) ||
2442 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2443 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2444 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2445 {
2446 return ipmi::responseParmOutOfRange();
2447 }
2448
Vernon Mauery15419dd2019-05-24 09:40:30 -07002449 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002450 try
2451 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002452 service = getService(*dbus, intf, objpath);
2453 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002454 }
2455 catch (const std::exception& e)
2456 {
2457 phosphor::logging::log<phosphor::logging::level::ERR>(
2458 "No object implements interface",
2459 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2460 phosphor::logging::entry("INTF=%s", intf));
2461 return ipmi::responseResponseError();
2462 }
2463
2464 if (valueTree.empty())
2465 {
2466 phosphor::logging::log<phosphor::logging::level::ERR>(
2467 "No object implements interface",
2468 phosphor::logging::entry("INTF=%s", intf));
2469 return ipmi::responseResponseError();
2470 }
2471
2472 for (const auto& item : valueTree)
2473 {
2474 // find LedFault configuration
2475 auto interface =
2476 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2477 if (interface == item.second.end())
2478 {
2479 continue;
2480 }
2481
2482 // find matched fault type: faultMemmory / faultFan
2483 // find LedGpioPins/FaultIndex configuration
2484 auto propertyFaultType = interface->second.find("FaultType");
2485 auto propertyFIndex = interface->second.find("FaultIndex");
2486 auto ledIndex = interface->second.find("LedGpioPins");
2487
2488 if (propertyFaultType == interface->second.end() ||
2489 propertyFIndex == interface->second.end() ||
2490 ledIndex == interface->second.end())
2491 {
2492 continue;
2493 }
2494
2495 try
2496 {
2497 Value valIndex = propertyFIndex->second;
2498 resFIndex = std::get<uint64_t>(valIndex);
2499
2500 Value valFType = propertyFaultType->second;
2501 resFType = std::get<std::string>(valFType);
2502 }
2503 catch (const std::bad_variant_access& e)
2504 {
2505 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2506 return ipmi::responseResponseError();
2507 }
2508 // find the matched requested fault type: faultMemmory or faultFan
2509 if (resFType != faultNames[faultType])
2510 {
2511 continue;
2512 }
2513
2514 // read LedGpioPins data
2515 std::vector<uint64_t> ledgpios;
2516 std::variant<std::vector<uint64_t>> message;
2517
Vernon Mauery15419dd2019-05-24 09:40:30 -07002518 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002519 service.c_str(), (std::string(item.first)).c_str(),
2520 "org.freedesktop.DBus.Properties", "Get");
2521
2522 method.append("xyz.openbmc_project.Configuration.LedFault",
2523 "LedGpioPins");
2524
2525 try
2526 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002527 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002528 reply.read(message);
2529 ledgpios = std::get<std::vector<uint64_t>>(message);
2530 }
2531 catch (std::exception& e)
2532 {
2533 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2534 return ipmi::responseResponseError();
2535 }
2536
2537 // Check the size to be sure it will never overflow on groupSize
2538 if (ledgpios.size() > groupSize)
2539 {
2540 phosphor::logging::log<phosphor::logging::level::ERR>(
2541 "Fault gpio Pins out of range!");
2542 return ipmi::responseParmOutOfRange();
2543 }
2544 // Store data, according to command data bit index order
2545 for (int i = 0; i < ledgpios.size(); i++)
2546 {
2547 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2548 }
2549 }
2550
2551 switch (RemoteFaultType(faultType))
2552 {
2553 case (RemoteFaultType::fan):
2554 case (RemoteFaultType::memory):
2555 {
2556 if (faultGroup == skipLEDs)
2557 {
2558 return ipmi::responseSuccess();
2559 }
2560
2561 uint64_t ledState = 0;
2562 // calculate led state bit filed count, each byte has 8bits
2563 // the maximum bits will be 8 * 8 bits
2564 constexpr uint8_t size = sizeof(ledStateData) * 8;
2565 for (int i = 0; i < sizeof(ledStateData); i++)
2566 {
2567 ledState = (uint64_t)(ledState << 8);
2568 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2569 }
2570
2571 std::bitset<size> ledStateBits(ledState);
2572 std::string gpioValue;
2573 for (int i = 0; i < size; i++)
2574 { // skip invalid value
2575 if (ledFaultPins[i] == 0xFFFF)
2576 {
2577 continue;
2578 }
2579
2580 std::string device = sysGpioPath +
2581 std::to_string(ledFaultPins[i]) +
2582 postfixValue;
2583 std::fstream gpioFile;
2584
2585 gpioFile.open(device, std::ios::out);
2586
2587 if (!gpioFile.good())
2588 {
2589 phosphor::logging::log<phosphor::logging::level::ERR>(
2590 "Not Find Led Gpio Device!",
2591 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2592 return ipmi::responseResponseError();
2593 }
2594 gpioFile << std::to_string(
2595 static_cast<uint8_t>(ledStateBits[i]));
2596 gpioFile.close();
2597 }
2598 break;
2599 }
2600 default:
2601 {
2602 // now only support two fault types
2603 return ipmi::responseParmOutOfRange();
2604 }
2605 }
2606
2607 return ipmi::responseSuccess();
2608}
2609
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302610ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2611{
2612 uint8_t prodId = 0;
2613 try
2614 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002615 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302616 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002617 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302618 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2619 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002620 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302621 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2622 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2623 }
2624 catch (std::exception& e)
2625 {
2626 phosphor::logging::log<phosphor::logging::level::ERR>(
2627 "ipmiOEMReadBoardProductId: Product ID read failed!",
2628 phosphor::logging::entry("ERR=%s", e.what()));
2629 }
2630 return ipmi::responseSuccess(prodId);
2631}
2632
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302633/** @brief implements the get security mode command
2634 * @param ctx - ctx pointer
2635 *
2636 * @returns IPMI completion code with following data
2637 * - restriction mode value - As specified in
2638 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2639 * - special mode value - As specified in
2640 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2641 */
2642ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2643{
2644 namespace securityNameSpace =
2645 sdbusplus::xyz::openbmc_project::Control::Security::server;
2646 uint8_t restrictionModeValue = 0;
2647 uint8_t specialModeValue = 0;
2648
2649 boost::system::error_code ec;
2650 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002651 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302652 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2653 restricionModeProperty);
2654 if (ec)
2655 {
2656 phosphor::logging::log<phosphor::logging::level::ERR>(
2657 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2658 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2659 return ipmi::responseUnspecifiedError();
2660 }
2661 restrictionModeValue = static_cast<uint8_t>(
2662 securityNameSpace::RestrictionMode::convertModesFromString(
2663 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302664 auto varSpecialMode =
2665 ctx->bus->yield_method_call<std::variant<std::string>>(
2666 ctx->yield, ec, specialModeService, specialModeBasePath,
2667 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2668 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302669 if (ec)
2670 {
2671 phosphor::logging::log<phosphor::logging::level::ERR>(
2672 "ipmiGetSecurityMode: failed to get SpecialMode property",
2673 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2674 // fall through, let us not worry about SpecialMode property, which is
2675 // not required in user scenario
2676 }
2677 else
2678 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302679 specialModeValue = static_cast<uint8_t>(
2680 securityNameSpace::SpecialMode::convertModesFromString(
2681 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302682 }
2683 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2684}
2685
2686/** @brief implements the set security mode command
2687 * Command allows to upgrade the restriction mode and won't allow
2688 * to downgrade from system interface
2689 * @param ctx - ctx pointer
2690 * @param restrictionMode - restriction mode value to be set.
2691 *
2692 * @returns IPMI completion code
2693 */
2694ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302695 uint8_t restrictionMode,
2696 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302697{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302698#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2699 if (specialMode)
2700 {
2701 return ipmi::responseReqDataLenInvalid();
2702 }
2703#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302704 namespace securityNameSpace =
2705 sdbusplus::xyz::openbmc_project::Control::Security::server;
2706
2707 ChannelInfo chInfo;
2708 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2709 {
2710 phosphor::logging::log<phosphor::logging::level::ERR>(
2711 "ipmiSetSecurityMode: Failed to get Channel Info",
2712 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2713 return ipmi::responseUnspecifiedError();
2714 }
2715 auto reqMode =
2716 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2717
2718 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2719 (reqMode >
2720 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2721 {
2722 return ipmi::responseInvalidFieldRequest();
2723 }
2724
2725 boost::system::error_code ec;
2726 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002727 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302728 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2729 restricionModeProperty);
2730 if (ec)
2731 {
2732 phosphor::logging::log<phosphor::logging::level::ERR>(
2733 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2734 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2735 return ipmi::responseUnspecifiedError();
2736 }
2737 auto currentRestrictionMode =
2738 securityNameSpace::RestrictionMode::convertModesFromString(
2739 std::get<std::string>(varRestrMode));
2740
2741 if (chInfo.mediumType !=
2742 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2743 currentRestrictionMode > reqMode)
2744 {
2745 phosphor::logging::log<phosphor::logging::level::ERR>(
2746 "ipmiSetSecurityMode - Downgrading security mode not supported "
2747 "through system interface",
2748 phosphor::logging::entry(
2749 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2750 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2751 return ipmi::responseCommandNotAvailable();
2752 }
2753
2754 ec.clear();
2755 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002756 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302757 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2758 restricionModeProperty,
2759 static_cast<std::variant<std::string>>(
2760 securityNameSpace::convertForMessage(reqMode)));
2761
2762 if (ec)
2763 {
2764 phosphor::logging::log<phosphor::logging::level::ERR>(
2765 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2766 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2767 return ipmi::responseUnspecifiedError();
2768 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302769
2770#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2771 if (specialMode)
2772 {
2773 ec.clear();
2774 ctx->bus->yield_method_call<>(
2775 ctx->yield, ec, specialModeService, specialModeBasePath,
2776 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2777 specialModeProperty,
2778 static_cast<std::variant<std::string>>(
2779 securityNameSpace::convertForMessage(
2780 static_cast<securityNameSpace::SpecialMode::Modes>(
2781 specialMode.value()))));
2782
2783 if (ec)
2784 {
2785 phosphor::logging::log<phosphor::logging::level::ERR>(
2786 "ipmiSetSecurityMode: failed to set SpecialMode property",
2787 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2788 return ipmi::responseUnspecifiedError();
2789 }
2790 }
2791#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302792 return ipmi::responseSuccess();
2793}
2794
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002795ipmi::RspType<uint8_t /* restore status */>
2796 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2797{
2798 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2799
2800 if (clr != expClr)
2801 {
2802 return ipmi::responseInvalidFieldRequest();
2803 }
2804 constexpr uint8_t cmdStatus = 0;
2805 constexpr uint8_t cmdDefaultRestore = 0xaa;
2806 constexpr uint8_t cmdFullRestore = 0xbb;
2807 constexpr uint8_t cmdFormat = 0xcc;
2808
2809 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2810
2811 switch (cmd)
2812 {
2813 case cmdStatus:
2814 break;
2815 case cmdDefaultRestore:
2816 case cmdFullRestore:
2817 case cmdFormat:
2818 {
2819 // write file to rwfs root
2820 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2821 std::ofstream restoreFile(restoreOpFname);
2822 if (!restoreFile)
2823 {
2824 return ipmi::responseUnspecifiedError();
2825 }
2826 restoreFile << value << "\n";
2827 break;
2828 }
2829 default:
2830 return ipmi::responseInvalidFieldRequest();
2831 }
2832
2833 constexpr uint8_t restorePending = 0;
2834 constexpr uint8_t restoreComplete = 1;
2835
2836 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2837 ? restorePending
2838 : restoreComplete;
2839 return ipmi::responseSuccess(restoreStatus);
2840}
2841
Chen Yugang39736d52019-07-12 16:24:33 +08002842ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2843{
2844 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002845 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002846
2847 try
2848 {
2849 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2850 std::string service =
2851 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2852 Value variant =
2853 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2854 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2855
2856 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2857 std::get<std::string>(variant)))
2858 {
2859 case nmi::NMISource::BMCSourceSignal::None:
2860 bmcSource = static_cast<uint8_t>(NmiSource::none);
2861 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002862 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2863 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002864 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002865 case nmi::NMISource::BMCSourceSignal::Watchdog:
2866 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002867 break;
2868 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2869 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2870 break;
2871 case nmi::NMISource::BMCSourceSignal::MemoryError:
2872 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2873 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002874 case nmi::NMISource::BMCSourceSignal::PciBusError:
2875 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002876 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002877 case nmi::NMISource::BMCSourceSignal::PCH:
2878 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002879 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002880 case nmi::NMISource::BMCSourceSignal::Chipset:
2881 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002882 break;
2883 default:
2884 phosphor::logging::log<phosphor::logging::level::ERR>(
2885 "NMI source: invalid property!",
2886 phosphor::logging::entry(
2887 "PROP=%s", std::get<std::string>(variant).c_str()));
2888 return ipmi::responseResponseError();
2889 }
2890 }
2891 catch (sdbusplus::exception::SdBusError& e)
2892 {
2893 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2894 return ipmi::responseResponseError();
2895 }
2896
2897 return ipmi::responseSuccess(bmcSource);
2898}
2899
2900ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2901{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002902 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002903
2904 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2905 nmi::NMISource::BMCSourceSignal::None;
2906
2907 switch (NmiSource(sourceId))
2908 {
2909 case NmiSource::none:
2910 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2911 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002912 case NmiSource::frontPanelButton:
2913 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08002914 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002915 case NmiSource::watchdog:
2916 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08002917 break;
2918 case NmiSource::chassisCmd:
2919 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2920 break;
2921 case NmiSource::memoryError:
2922 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2923 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002924 case NmiSource::pciBusError:
2925 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08002926 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002927 case NmiSource::pch:
2928 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08002929 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002930 case NmiSource::chipset:
2931 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08002932 break;
2933 default:
2934 phosphor::logging::log<phosphor::logging::level::ERR>(
2935 "NMI source: invalid property!");
2936 return ipmi::responseResponseError();
2937 }
2938
2939 try
2940 {
2941 // keep NMI signal source
2942 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2943 std::string service =
2944 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08002945 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2946 oemNmiBmcSourceObjPathProp,
2947 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002948 // set Enabled property to inform NMI source handling
2949 // to trigger a NMI_OUT BSOD.
2950 // if it's triggered by NMI source property changed,
2951 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2952 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2953 {
2954 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2955 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2956 static_cast<bool>(true));
2957 }
Chen Yugang39736d52019-07-12 16:24:33 +08002958 }
2959 catch (sdbusplus::exception_t& e)
2960 {
2961 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2962 return ipmi::responseResponseError();
2963 }
2964
2965 return ipmi::responseSuccess();
2966}
2967
James Feist63efafa2019-07-24 12:39:21 -07002968namespace dimmOffset
2969{
2970constexpr const char* dimmPower = "DimmPower";
2971constexpr const char* staticCltt = "StaticCltt";
2972constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2973constexpr const char* offsetInterface =
2974 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2975constexpr const char* property = "DimmOffset";
2976
2977}; // namespace dimmOffset
2978
2979ipmi::RspType<>
2980 ipmiOEMSetDimmOffset(uint8_t type,
2981 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2982{
2983 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2984 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2985 {
2986 return ipmi::responseInvalidFieldRequest();
2987 }
2988
2989 if (data.empty())
2990 {
2991 return ipmi::responseInvalidFieldRequest();
2992 }
2993 nlohmann::json json;
2994
2995 std::ifstream jsonStream(dimmOffsetFile);
2996 if (jsonStream.good())
2997 {
2998 json = nlohmann::json::parse(jsonStream, nullptr, false);
2999 if (json.is_discarded())
3000 {
3001 json = nlohmann::json();
3002 }
3003 jsonStream.close();
3004 }
3005
3006 std::string typeName;
3007 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3008 {
3009 typeName = dimmOffset::dimmPower;
3010 }
3011 else
3012 {
3013 typeName = dimmOffset::staticCltt;
3014 }
3015
3016 nlohmann::json& field = json[typeName];
3017
3018 for (const auto& [index, value] : data)
3019 {
3020 field[index] = value;
3021 }
3022
3023 for (nlohmann::json& val : field)
3024 {
3025 if (val == nullptr)
3026 {
3027 val = static_cast<uint8_t>(0);
3028 }
3029 }
3030
3031 std::ofstream output(dimmOffsetFile);
3032 if (!output.good())
3033 {
3034 std::cerr << "Error writing json file\n";
3035 return ipmi::responseResponseError();
3036 }
3037
3038 output << json.dump(4);
3039
3040 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3041 {
3042 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3043
3044 std::variant<std::vector<uint8_t>> offsets =
3045 field.get<std::vector<uint8_t>>();
3046 auto call = bus->new_method_call(
3047 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3048 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3049 try
3050 {
3051 bus->call(call);
3052 }
3053 catch (sdbusplus::exception_t& e)
3054 {
3055 phosphor::logging::log<phosphor::logging::level::ERR>(
3056 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3057 phosphor::logging::entry("ERR=%s", e.what()));
3058 return ipmi::responseResponseError();
3059 }
3060 }
3061
3062 return ipmi::responseSuccess();
3063}
3064
3065ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3066{
3067
3068 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3069 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3070 {
3071 return ipmi::responseInvalidFieldRequest();
3072 }
3073
3074 std::ifstream jsonStream(dimmOffsetFile);
3075
3076 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3077 if (json.is_discarded())
3078 {
3079 std::cerr << "File error in " << dimmOffsetFile << "\n";
3080 return ipmi::responseResponseError();
3081 }
3082
3083 std::string typeName;
3084 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3085 {
3086 typeName = dimmOffset::dimmPower;
3087 }
3088 else
3089 {
3090 typeName = dimmOffset::staticCltt;
3091 }
3092
3093 auto it = json.find(typeName);
3094 if (it == json.end())
3095 {
3096 return ipmi::responseInvalidFieldRequest();
3097 }
3098
3099 if (it->size() <= index)
3100 {
3101 return ipmi::responseInvalidFieldRequest();
3102 }
3103
3104 uint8_t resp = it->at(index).get<uint8_t>();
3105 return ipmi::responseSuccess(resp);
3106}
3107
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003108namespace boot_options
3109{
3110
3111using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3112using IpmiValue = uint8_t;
3113constexpr auto ipmiDefault = 0;
3114
3115std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3116 {0x01, Source::Sources::Network},
3117 {0x02, Source::Sources::Disk},
3118 {0x05, Source::Sources::ExternalMedia},
3119 {0x0f, Source::Sources::RemovableMedia},
3120 {ipmiDefault, Source::Sources::Default}};
3121
3122std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003123 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003124
3125std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3126 {Source::Sources::Network, 0x01},
3127 {Source::Sources::Disk, 0x02},
3128 {Source::Sources::ExternalMedia, 0x05},
3129 {Source::Sources::RemovableMedia, 0x0f},
3130 {Source::Sources::Default, ipmiDefault}};
3131
3132std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003133 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003134
3135static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3136static constexpr auto bootSourceIntf =
3137 "xyz.openbmc_project.Control.Boot.Source";
3138static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3139static constexpr auto persistentObjPath =
3140 "/xyz/openbmc_project/control/host0/boot";
3141static constexpr auto oneTimePath =
3142 "/xyz/openbmc_project/control/host0/boot/one_time";
3143static constexpr auto bootSourceProp = "BootSource";
3144static constexpr auto bootModeProp = "BootMode";
3145static constexpr auto oneTimeBootEnableProp = "Enabled";
3146static constexpr auto httpBootMode =
3147 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3148
3149enum class BootOptionParameter : size_t
3150{
3151 setInProgress = 0x0,
3152 bootFlags = 0x5,
3153};
3154static constexpr uint8_t setComplete = 0x0;
3155static constexpr uint8_t setInProgress = 0x1;
3156static uint8_t transferStatus = setComplete;
3157static constexpr uint8_t setParmVersion = 0x01;
3158static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3159static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3160static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3161static constexpr uint8_t httpBoot = 0xd;
3162static constexpr uint8_t bootSourceMask = 0x3c;
3163
3164} // namespace boot_options
3165
3166ipmi::RspType<uint8_t, // version
3167 uint8_t, // param
3168 uint8_t, // data0, dependent on parameter
3169 std::optional<uint8_t> // data1, dependent on parameter
3170 >
3171 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3172{
3173 using namespace boot_options;
3174 uint8_t bootOption = 0;
3175
3176 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3177 {
3178 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3179 std::nullopt);
3180 }
3181
3182 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3183 {
3184 phosphor::logging::log<phosphor::logging::level::ERR>(
3185 "Unsupported parameter");
3186 return ipmi::responseResponseError();
3187 }
3188
3189 try
3190 {
3191 auto oneTimeEnabled = false;
3192 // read one time Enabled property
3193 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3194 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3195 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3196 enabledIntf, oneTimeBootEnableProp);
3197 oneTimeEnabled = std::get<bool>(variant);
3198
3199 // get BootSource and BootMode properties
3200 // according to oneTimeEnable
3201 auto bootObjPath = oneTimePath;
3202 if (oneTimeEnabled == false)
3203 {
3204 bootObjPath = persistentObjPath;
3205 }
3206
3207 service = getService(*dbus, bootModeIntf, bootObjPath);
3208 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3209 bootModeProp);
3210
3211 auto bootMode =
3212 Mode::convertModesFromString(std::get<std::string>(variant));
3213
3214 service = getService(*dbus, bootSourceIntf, bootObjPath);
3215 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3216 bootSourceProp);
3217
3218 if (std::get<std::string>(variant) == httpBootMode)
3219 {
3220 bootOption = httpBoot;
3221 }
3222 else
3223 {
3224 auto bootSource = Source::convertSourcesFromString(
3225 std::get<std::string>(variant));
3226 bootOption = sourceDbusToIpmi.at(bootSource);
3227 if (Source::Sources::Default == bootSource)
3228 {
3229 bootOption = modeDbusToIpmi.at(bootMode);
3230 }
3231 }
3232
3233 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3234 : setParmBootFlagsValidPermanent;
3235 bootOption <<= 2; // shift for responseconstexpr
3236 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3237 bootOption);
3238 }
3239 catch (sdbusplus::exception_t& e)
3240 {
3241 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3242 return ipmi::responseResponseError();
3243 }
3244}
3245
3246ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3247 std::optional<uint8_t> bootOption)
3248{
3249 using namespace boot_options;
3250 auto oneTimeEnabled = false;
3251
3252 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3253 {
3254 if (bootOption)
3255 {
3256 return ipmi::responseReqDataLenInvalid();
3257 }
3258
3259 if (transferStatus == setInProgress)
3260 {
3261 phosphor::logging::log<phosphor::logging::level::ERR>(
3262 "boot option set in progress!");
3263 return ipmi::responseResponseError();
3264 }
3265
3266 transferStatus = bootParam;
3267 return ipmi::responseSuccess();
3268 }
3269
3270 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3271 {
3272 phosphor::logging::log<phosphor::logging::level::ERR>(
3273 "Unsupported parameter");
3274 return ipmi::responseResponseError();
3275 }
3276
3277 if (!bootOption)
3278 {
3279 return ipmi::responseReqDataLenInvalid();
3280 }
3281
3282 if (((bootOption.value() & bootSourceMask) >> 2) !=
3283 httpBoot) // not http boot, exit
3284 {
3285 phosphor::logging::log<phosphor::logging::level::ERR>(
3286 "wrong boot option parameter!");
3287 return ipmi::responseParmOutOfRange();
3288 }
3289
3290 try
3291 {
3292 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3293 setParmBootFlagsPermanent;
3294
3295 // read one time Enabled property
3296 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3297 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3298 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3299 enabledIntf, oneTimeBootEnableProp);
3300 oneTimeEnabled = std::get<bool>(variant);
3301
3302 /*
3303 * Check if the current boot setting is onetime or permanent, if the
3304 * request in the command is otherwise, then set the "Enabled"
3305 * property in one_time object path to 'True' to indicate onetime
3306 * and 'False' to indicate permanent.
3307 *
3308 * Once the onetime/permanent setting is applied, then the bootMode
3309 * and bootSource is updated for the corresponding object.
3310 */
3311 if (permanent == oneTimeEnabled)
3312 {
3313 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3314 oneTimeBootEnableProp, !permanent);
3315 }
3316
3317 // set BootSource and BootMode properties
3318 // according to oneTimeEnable or persistent
3319 auto bootObjPath = oneTimePath;
3320 if (oneTimeEnabled == false)
3321 {
3322 bootObjPath = persistentObjPath;
3323 }
3324 std::string bootMode =
3325 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3326 std::string bootSource = httpBootMode;
3327
3328 service = getService(*dbus, bootModeIntf, bootObjPath);
3329 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3330 bootMode);
3331
3332 service = getService(*dbus, bootSourceIntf, bootObjPath);
3333 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3334 bootSourceProp, bootSource);
3335 }
3336 catch (sdbusplus::exception_t& e)
3337 {
3338 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3339 return ipmi::responseResponseError();
3340 }
3341
3342 return ipmi::responseSuccess();
3343}
3344
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003345using BasicVariantType =
3346 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3347 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3348 uint16_t, uint8_t, bool>;
3349using PropertyMapType =
3350 boost::container::flat_map<std::string, BasicVariantType>;
3351static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3352 "xyz.openbmc_project.Configuration.PSUPresence"};
3353int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3354 std::vector<uint64_t>& addrTable)
3355{
3356 boost::system::error_code ec;
3357 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3358 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3359 "/xyz/openbmc_project/object_mapper",
3360 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3361 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3362 if (ec)
3363 {
3364 phosphor::logging::log<phosphor::logging::level::ERR>(
3365 "Failed to set dbus property to cold redundancy");
3366 return -1;
3367 }
3368 for (const auto& object : subtree)
3369 {
3370 std::string pathName = object.first;
3371 for (const auto& serviceIface : object.second)
3372 {
3373 std::string serviceName = serviceIface.first;
3374
3375 ec.clear();
3376 PropertyMapType propMap =
3377 ctx->bus->yield_method_call<PropertyMapType>(
3378 ctx->yield, ec, serviceName, pathName,
3379 "org.freedesktop.DBus.Properties", "GetAll",
3380 "xyz.openbmc_project.Configuration.PSUPresence");
3381 if (ec)
3382 {
3383 phosphor::logging::log<phosphor::logging::level::ERR>(
3384 "Failed to set dbus property to cold redundancy");
3385 return -1;
3386 }
3387 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3388 auto psuAddress =
3389 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3390
3391 if (psuBus == nullptr || psuAddress == nullptr)
3392 {
3393 std::cerr << "error finding necessary "
3394 "entry in configuration\n";
3395 return -1;
3396 }
3397 bus = static_cast<uint8_t>(*psuBus);
3398 addrTable = *psuAddress;
3399 return 0;
3400 }
3401 }
3402 return -1;
3403}
3404
3405static const constexpr uint8_t addrOffset = 8;
3406static const constexpr uint8_t psuRevision = 0xd9;
3407static const constexpr uint8_t defaultPSUBus = 7;
3408// Second Minor, Primary Minor, Major
3409static const constexpr size_t verLen = 3;
3410ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3411{
3412 uint8_t bus = defaultPSUBus;
3413 std::vector<uint64_t> addrTable;
3414 std::vector<uint8_t> result;
3415 if (getPSUAddress(ctx, bus, addrTable))
3416 {
3417 std::cerr << "Failed to get PSU bus and address\n";
3418 return ipmi::responseResponseError();
3419 }
3420
3421 for (const auto& slaveAddr : addrTable)
3422 {
3423 std::vector<uint8_t> writeData = {psuRevision};
3424 std::vector<uint8_t> readBuf(verLen);
3425 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3426 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3427
3428 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3429 if (retI2C != ipmi::ccSuccess)
3430 {
3431 for (size_t idx = 0; idx < verLen; idx++)
3432 {
3433 result.emplace_back(0x00);
3434 }
3435 }
3436 else
3437 {
3438 for (const uint8_t& data : readBuf)
3439 {
3440 result.emplace_back(data);
3441 }
3442 }
3443 }
3444
3445 return ipmi::responseSuccess(result);
3446}
3447
AppaRao Puli28972062019-11-11 02:04:45 +05303448/** @brief implements the maximum size of
3449 * bridgeable messages used between KCS and
3450 * IPMB interfacesget security mode command.
3451 *
3452 * @returns IPMI completion code with following data
3453 * - KCS Buffer Size (In multiples of four bytes)
3454 * - IPMB Buffer Size (In multiples of four bytes)
3455 **/
3456ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3457{
3458 // for now this is hard coded; really this number is dependent on
3459 // the BMC kcs driver as well as the host kcs driver....
3460 // we can't know the latter.
3461 uint8_t kcsMaxBufferSize = 63 / 4;
3462 uint8_t ipmbMaxBufferSize = 128 / 4;
3463
3464 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3465}
3466
Jason M. Bills64796042018-10-03 16:51:55 -07003467static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003468{
3469 phosphor::logging::log<phosphor::logging::level::INFO>(
3470 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003471 ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003472 ipmiOEMWildcard,
3473 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003474
3475 ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003476 ipmiOEMWildcard,
3477 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003478
3479 ipmiPrintAndRegister(intel::netFnGeneral,
3480 intel::general::cmdGetChassisIdentifier, NULL,
3481 ipmiOEMGetChassisIdentifier,
3482 PRIVILEGE_USER); // get chassis identifier
3483
3484 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3485 NULL, ipmiOEMSetSystemGUID,
3486 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003487
3488 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003489 registerHandler(prioOemBase, intel::netFnGeneral,
3490 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3491 ipmiOEMDisableBMCSystemReset);
3492
Jason M. Billsb02bf092019-08-15 13:01:56 -07003493 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003494 registerHandler(prioOemBase, intel::netFnGeneral,
3495 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3496 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003497
Vernon Mauery98bbf692019-09-16 11:14:59 -07003498 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3499 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003500
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003501 registerHandler(prioOemBase, intel::netFnGeneral,
3502 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3503 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003504
Vernon Mauery98bbf692019-09-16 11:14:59 -07003505 ipmiPrintAndRegister(intel::netFnGeneral,
3506 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3507 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303508
Vernon Mauery98bbf692019-09-16 11:14:59 -07003509 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3510 intel::general::cmdSendEmbeddedFWUpdStatus,
3511 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303512
Vernon Mauery98bbf692019-09-16 11:14:59 -07003513 ipmiPrintAndRegister(intel::netFnGeneral,
3514 intel::general::cmdSetPowerRestoreDelay, NULL,
3515 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3516
3517 ipmiPrintAndRegister(intel::netFnGeneral,
3518 intel::general::cmdGetPowerRestoreDelay, NULL,
3519 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3520
3521 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3522 intel::general::cmdSetOEMUser2Activation,
3523 Privilege::Callback, ipmiOEMSetUser2Activation);
3524
3525 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3526 intel::general::cmdSetSpecialUserPassword,
3527 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303528
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003529 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003530 registerHandler(prioOemBase, intel::netFnGeneral,
3531 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3532 ipmiOEMGetProcessorErrConfig);
3533
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003534 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003535 registerHandler(prioOemBase, intel::netFnGeneral,
3536 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3537 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003538
Vernon Mauery98bbf692019-09-16 11:14:59 -07003539 ipmiPrintAndRegister(intel::netFnGeneral,
3540 intel::general::cmdSetShutdownPolicy, NULL,
3541 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003542
Vernon Mauery98bbf692019-09-16 11:14:59 -07003543 ipmiPrintAndRegister(intel::netFnGeneral,
3544 intel::general::cmdGetShutdownPolicy, NULL,
3545 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003546
anil kumar appanaf945eee2019-09-25 23:29:11 +00003547 registerHandler(prioOemBase, intel::netFnGeneral,
3548 intel::general::cmdSetFanConfig, Privilege::User,
3549 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003550
Vernon Mauery98bbf692019-09-16 11:14:59 -07003551 registerHandler(prioOemBase, intel::netFnGeneral,
3552 intel::general::cmdGetFanConfig, Privilege::User,
3553 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003554
Vernon Mauery98bbf692019-09-16 11:14:59 -07003555 registerHandler(prioOemBase, intel::netFnGeneral,
3556 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3557 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003558
Vernon Mauery98bbf692019-09-16 11:14:59 -07003559 registerHandler(prioOemBase, intel::netFnGeneral,
3560 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3561 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003562
Vernon Mauery98bbf692019-09-16 11:14:59 -07003563 registerHandler(prioOemBase, intel::netFnGeneral,
3564 intel::general::cmdSetFscParameter, Privilege::User,
3565 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003566
Vernon Mauery98bbf692019-09-16 11:14:59 -07003567 registerHandler(prioOemBase, intel::netFnGeneral,
3568 intel::general::cmdGetFscParameter, Privilege::User,
3569 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303570
Vernon Mauery98bbf692019-09-16 11:14:59 -07003571 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3572 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3573 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003574
Vernon Mauery98bbf692019-09-16 11:14:59 -07003575 registerHandler(prioOemBase, intel::netFnGeneral,
3576 intel::general::cmdGetNmiStatus, Privilege::User,
3577 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003578
Vernon Mauery98bbf692019-09-16 11:14:59 -07003579 registerHandler(prioOemBase, intel::netFnGeneral,
3580 intel::general::cmdSetNmiStatus, Privilege::Operator,
3581 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003582
Vernon Mauery98bbf692019-09-16 11:14:59 -07003583 registerHandler(prioOemBase, intel::netFnGeneral,
3584 intel::general::cmdGetEfiBootOptions, Privilege::User,
3585 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003586
Vernon Mauery98bbf692019-09-16 11:14:59 -07003587 registerHandler(prioOemBase, intel::netFnGeneral,
3588 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3589 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303590
Vernon Mauery98bbf692019-09-16 11:14:59 -07003591 registerHandler(prioOemBase, intel::netFnGeneral,
3592 intel::general::cmdGetSecurityMode, Privilege::User,
3593 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303594
Vernon Mauery98bbf692019-09-16 11:14:59 -07003595 registerHandler(prioOemBase, intel::netFnGeneral,
3596 intel::general::cmdSetSecurityMode, Privilege::Admin,
3597 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003598
Vernon Mauery98bbf692019-09-16 11:14:59 -07003599 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3600 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003601
Vernon Mauery98bbf692019-09-16 11:14:59 -07003602 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3603 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3604 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3605
3606 registerHandler(prioOemBase, intel::netFnGeneral,
3607 intel::general::cmdSetFaultIndication, Privilege::Operator,
3608 ipmiOEMSetFaultIndication);
3609
3610 registerHandler(prioOemBase, intel::netFnGeneral,
3611 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3612 ipmiOEMSetCRConfig);
3613
3614 registerHandler(prioOemBase, intel::netFnGeneral,
3615 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3616 ipmiOEMGetCRConfig);
3617
3618 registerHandler(prioOemBase, intel::netFnGeneral,
3619 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003620 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003621
Vernon Mauery98bbf692019-09-16 11:14:59 -07003622 registerHandler(prioOemBase, intel::netFnGeneral,
3623 intel::general::cmdSetDimmOffset, Privilege::Operator,
3624 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003625
Vernon Mauery98bbf692019-09-16 11:14:59 -07003626 registerHandler(prioOemBase, intel::netFnGeneral,
3627 intel::general::cmdGetDimmOffset, Privilege::Operator,
3628 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003629
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003630 registerHandler(prioOemBase, intel::netFnGeneral,
3631 intel::general::cmdGetPSUVersion, Privilege::User,
3632 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303633
3634 registerHandler(prioOemBase, intel::netFnGeneral,
3635 intel::general::cmdGetBufferSize, Privilege::User,
3636 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003637}
3638
3639} // namespace ipmi