blob: aa99fedb60068c17b6f0ac9c087ed36fd8980491 [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
Patrick Venturec2a07d42020-05-30 16:35:03 -070017#include "types.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070018#include "xyz/openbmc_project/Common/error.hpp"
Kuiying Wang45f04982018-12-26 09:23:08 +080019#include "xyz/openbmc_project/Led/Physical/server.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070020
Jayaprakash Mutyala94204162020-10-23 06:17:56 +000021#include <openssl/crypto.h>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080022#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080023
Chen Yugang7a04f3a2019-10-08 11:12:35 +080024#include <appcommands.hpp>
James Feist91244a62019-02-19 15:04:54 -080025#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080026#include <boost/process/child.hpp>
27#include <boost/process/io.hpp>
Yong Li0669d192019-05-06 14:01:46 +080028#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070029#include <commandutils.hpp>
Zhikui Rence4e73f2019-12-06 13:59:47 -080030#include <gpiod.hpp>
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>
36#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053037#include <sdbusplus/message/types.hpp>
Chen Yugang97cf96e2019-11-01 08:55:11 +080038#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080039#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
40#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080041#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053042#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053043#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080044
James Feistfcd2d3a2020-05-28 10:38:15 -070045#include <array>
46#include <filesystem>
47#include <iostream>
48#include <regex>
49#include <string>
50#include <variant>
51#include <vector>
52
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080053namespace ipmi
54{
Jason M. Bills64796042018-10-03 16:51:55 -070055static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070056
Jason M. Bills64796042018-10-03 16:51:55 -070057static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080058
Suryakanth Sekard509eb92018-11-15 17:44:11 +053059static constexpr auto ethernetIntf =
60 "xyz.openbmc_project.Network.EthernetInterface";
61static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
62static constexpr auto networkService = "xyz.openbmc_project.Network";
63static constexpr auto networkRoot = "/xyz/openbmc_project/network";
64
Chen Yugang97cf96e2019-11-01 08:55:11 +080065static constexpr const char* oemNmiSourceIntf =
66 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080067static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080068 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080069static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
70static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
71
James Feist63efafa2019-07-24 12:39:21 -070072static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
srikanta mondal2030d7c2020-05-03 17:25:25 +000073static constexpr const char* multiNodeObjPath =
74 "/xyz/openbmc_project/MultiNode/Status";
75static constexpr const char* multiNodeIntf =
76 "xyz.openbmc_project.Chassis.MultiNode";
James Feist63efafa2019-07-24 12:39:21 -070077
Chen Yugang39736d52019-07-12 16:24:33 +080078enum class NmiSource : uint8_t
79{
80 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080081 frontPanelButton = 1,
82 watchdog = 2,
83 chassisCmd = 3,
84 memoryError = 4,
85 pciBusError = 5,
86 pch = 6,
87 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080088};
89
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053090enum class SpecialUserIndex : uint8_t
91{
92 rootUser = 0,
93 atScaleDebugUser = 1
94};
95
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053096static constexpr const char* restricionModeService =
97 "xyz.openbmc_project.RestrictionMode.Manager";
98static constexpr const char* restricionModeBasePath =
99 "/xyz/openbmc_project/control/security/restriction_mode";
100static constexpr const char* restricionModeIntf =
101 "xyz.openbmc_project.Control.Security.RestrictionMode";
102static constexpr const char* restricionModeProperty = "RestrictionMode";
103
104static constexpr const char* specialModeService =
105 "xyz.openbmc_project.SpecialMode";
106static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530107 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530108static constexpr const char* specialModeIntf =
109 "xyz.openbmc_project.Security.SpecialMode";
110static constexpr const char* specialModeProperty = "SpecialMode";
111
112static constexpr const char* dBusPropertyIntf =
113 "org.freedesktop.DBus.Properties";
114static constexpr const char* dBusPropertyGetMethod = "Get";
115static constexpr const char* dBusPropertySetMethod = "Set";
116
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800117// return code: 0 successful
118int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
119{
120 std::string objpath = "/xyz/openbmc_project/FruDevice";
121 std::string intf = "xyz.openbmc_project.FruDeviceManager";
122 std::string service = getService(bus, intf, objpath);
123 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
124 if (valueTree.empty())
125 {
126 phosphor::logging::log<phosphor::logging::level::ERR>(
127 "No object implements interface",
128 phosphor::logging::entry("INTF=%s", intf.c_str()));
129 return -1;
130 }
131
Jason M. Bills64796042018-10-03 16:51:55 -0700132 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800133 {
134 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
135 if (interface == item.second.end())
136 {
137 continue;
138 }
139
140 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
141 if (property == interface->second.end())
142 {
143 continue;
144 }
145
146 try
147 {
148 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700149 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700150 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800151 {
152 phosphor::logging::log<phosphor::logging::level::ERR>(
153 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154 return -1;
155 }
Jason M. Bills64796042018-10-03 16:51:55 -0700156 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800157 return 0;
158 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500159 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800160 {
Jason M. Bills64796042018-10-03 16:51:55 -0700161 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162 return -1;
163 }
164 }
165 return -1;
166}
Jason M. Bills64796042018-10-03 16:51:55 -0700167
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800168// Returns the Chassis Identifier (serial #)
169ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
170 ipmi_request_t request,
171 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700172 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800173 ipmi_context_t context)
174{
175 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700176 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 {
Jason M. Bills64796042018-10-03 16:51:55 -0700178 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 return IPMI_CC_REQ_DATA_LEN_INVALID;
180 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700181 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
182 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 {
Jason M. Bills64796042018-10-03 16:51:55 -0700184 *dataLen = serial.size(); // length will never exceed response length
185 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800186 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700187 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800188 return IPMI_CC_OK;
189 }
Jason M. Bills64796042018-10-03 16:51:55 -0700190 *dataLen = 0;
191 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192}
193
194ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195 ipmi_request_t request,
196 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700197 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800198{
199 static constexpr size_t safeBufferLength = 50;
200 char buf[safeBufferLength] = {0};
201 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
202
Jason M. Bills64796042018-10-03 16:51:55 -0700203 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800204 {
Jason M. Bills64796042018-10-03 16:51:55 -0700205 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800206 return IPMI_CC_REQ_DATA_LEN_INVALID;
207 }
208
Jason M. Bills64796042018-10-03 16:51:55 -0700209 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800210
211 snprintf(
212 buf, safeBufferLength,
213 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
214 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
215 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
216 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
217 Data->node3, Data->node2, Data->node1);
218 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
219 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800220
221 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
222 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700223 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
224 std::string service = getService(*dbus, intf, objpath);
225 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800226 return IPMI_CC_OK;
227}
228
Jason M. Billsb02bf092019-08-15 13:01:56 -0700229ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
230 uint7_t reserved1)
231{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000232 if (reserved1)
233 {
234 return ipmi::responseInvalidFieldRequest();
235 }
236
Jason M. Billsb02bf092019-08-15 13:01:56 -0700237 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
238
239 try
240 {
241 auto service =
242 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
243 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
244 bmcResetDisablesIntf, "ResetOnSMI",
245 !disableResetOnSMI);
246 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500247 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700248 {
249 phosphor::logging::log<phosphor::logging::level::ERR>(
250 "Failed to set BMC reset disables",
251 phosphor::logging::entry("EXCEPTION=%s", e.what()));
252 return ipmi::responseUnspecifiedError();
253 }
254
255 return ipmi::responseSuccess();
256}
257
258ipmi::RspType<bool, // disableResetOnSMI
259 uint7_t // reserved
260 >
261 ipmiOEMGetBMCResetDisables()
262{
263 bool disableResetOnSMI = true;
264
265 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
266 try
267 {
268 auto service =
269 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
270 Value variant =
271 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
272 bmcResetDisablesIntf, "ResetOnSMI");
273 disableResetOnSMI = !std::get<bool>(variant);
274 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500275 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700276 {
277 phosphor::logging::log<phosphor::logging::level::ERR>(
278 "Failed to get BMC reset disables",
279 phosphor::logging::entry("EXCEPTION=%s", e.what()));
280 return ipmi::responseUnspecifiedError();
281 }
282
283 return ipmi::responseSuccess(disableResetOnSMI, 0);
284}
285
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800286ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
287 ipmi_request_t request, ipmi_response_t response,
288 ipmi_data_len_t dataLen, ipmi_context_t context)
289{
290 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
291
Jason M. Bills64796042018-10-03 16:51:55 -0700292 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800294 *dataLen = 0;
295 return IPMI_CC_REQ_DATA_LEN_INVALID;
296 }
Jason M. Bills64796042018-10-03 16:51:55 -0700297 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000298 for (auto idChar : idString)
299 {
300 if (!std::isprint(static_cast<unsigned char>(idChar)))
301 {
302 phosphor::logging::log<phosphor::logging::level::ERR>(
303 "BIOS ID contains non printable character");
304 return IPMI_CC_INVALID_FIELD_REQUEST;
305 }
306 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307
Vernon Mauery15419dd2019-05-24 09:40:30 -0700308 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000309 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
310 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800311 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800312 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
313 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700314 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 *dataLen = 1;
316 return IPMI_CC_OK;
317}
318
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000319bool getActiveHSCSoftwareVersionInfo(std::string& hscVersion, size_t hscNumber)
320{
321 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
322 try
323 {
324 std::string hsbpObjPath =
325 "/xyz/openbmc_project/software/HSBP_" + std::to_string(hscNumber);
326 auto service = getService(*dbus, biosVersionIntf, hsbpObjPath);
327 Value hscVersionValue =
328 getDbusProperty(*dbus, "xyz.openbmc_project.HsbpManager",
329 hsbpObjPath, biosVersionIntf, "Version");
330 hscVersion = std::get<std::string>(hscVersionValue);
331 }
332 catch (const sdbusplus::exception::exception& e)
333 {
334 phosphor::logging::log<phosphor::logging::level::INFO>(
335 "Failed to retrieve HSBP version information",
336 phosphor::logging::entry("HSBP Number=%d", hscNumber));
337 return false;
338 }
339 return true;
340}
341
342bool getHscVerInfo(ipmi::Context::ptr ctx, uint8_t& hsc0Major,
343 uint8_t& hsc0Minor, uint8_t& hsc1Major, uint8_t& hsc1Minor,
344 uint8_t& hsc2Major, uint8_t& hsc2Minor)
345{
346 std::string hscVersion;
347 std::array<uint8_t, 6> hscVersions{0};
348
349 for (size_t hscNumber = 1; hscNumber <= 3; hscNumber++)
350 {
351 if (!getActiveHSCSoftwareVersionInfo(hscVersion, hscNumber))
352 {
353 continue;
354 }
355 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?)");
356 constexpr size_t matchedPhosphor = 4;
357 std::smatch results;
358 // hscVersion = BOOT_VER.FPGA_VER.SECURITY_REVISION (Example: 00.02.01)
359 if (std::regex_match(hscVersion, results, pattern1))
360 {
361 // Major version is FPGA_VER and Minor version is SECURITY_REV
362 if (results.size() == matchedPhosphor)
363 {
364 int index = (hscNumber - 1) * 2;
365 hscVersions[index] =
366 static_cast<uint8_t>(std::stoi(results[2]));
367 hscVersions[index + 1] =
368 static_cast<uint8_t>(std::stoi(results[3]));
369 }
370 }
371 }
372 hsc0Major = hscVersions[0];
373 hsc0Minor = hscVersions[1];
374 hsc1Major = hscVersions[2];
375 hsc1Minor = hscVersions[3];
376 hsc2Major = hscVersions[4];
377 hsc2Minor = hscVersions[5];
378 return true;
379}
380
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530381bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
382 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800383{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800384 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530385 std::string bmcVersion;
386 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800387 {
388 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800389 }
390
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530391 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800392 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800393 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800394 MetaRevision revision = rev.value();
395 bmcMajor = revision.major;
396
397 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
398 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
399 }
400
401 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530402 std::string meVersion;
403 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800404 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800405 return false;
406 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530407 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
408 constexpr size_t matchedPhosphor = 6;
409 std::smatch results;
410 if (std::regex_match(meVersion, results, pattern1))
411 {
412 if (results.size() == matchedPhosphor)
413 {
414 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
Jayaprakash Mutyalad0657022021-08-26 21:18:08 +0000415 meMinor = static_cast<uint8_t>(std::stoi(results[2]) << 4 |
416 std::stoi(results[3]));
AppaRao Puli32825a22020-01-17 15:52:41 +0530417 }
418 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800419 return true;
420}
421
422ipmi::RspType<
423 std::variant<std::string,
424 std::tuple<uint8_t, std::array<uint8_t, 2>,
425 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
426 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
427 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530428 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
429 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530430 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800431{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800432 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
433 {
434 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800435 }
436
437 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800438 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800439 {
440 case OEMDevEntityType::biosId:
441 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530442 // Byte 2&3, Only used with selecting BIOS
443 if (!countToRead || !offset)
444 {
445 return ipmi::responseReqDataLenInvalid();
446 }
447
Vernon Mauery15419dd2019-05-24 09:40:30 -0700448 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800449 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000450 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800451 try
452 {
Yong Li2742b852019-12-16 14:55:11 +0800453 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000454 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800455 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700456 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530457 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800458 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800459 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800460 }
Jason M. Bills64796042018-10-03 16:51:55 -0700461 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530462 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700463 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530464 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700465 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800466 else
467 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530468 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800469 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800470
471 std::string readBuf = {0};
472 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530473 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800474 (readBuf.begin()));
475 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800476 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500477 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800478 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800479 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800480 }
481 }
482 break;
483
484 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800485 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530486 // Byte 2&3, Only used with selecting BIOS
487 if (countToRead || offset)
488 {
489 return ipmi::responseReqDataLenInvalid();
490 }
491
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800492 constexpr const size_t verLen = 2;
493 constexpr const size_t verTotalLen = 10;
494 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
495 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
496 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
497 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
498 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
499 // data0/1: BMC version number; data6/7: ME version number
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530500 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800501 {
502 return ipmi::responseUnspecifiedError();
503 }
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000504 if (!getHscVerInfo(ctx, hsc0Buf[0], hsc0Buf[1], hsc1Buf[0],
505 hsc1Buf[1], hsc2Buf[0], hsc2Buf[1]))
506 {
507 return ipmi::responseUnspecifiedError();
508 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800509 return ipmi::responseSuccess(
510 std::tuple<
511 uint8_t, std::array<uint8_t, verLen>,
512 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
513 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
514 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
515 }
516 break;
517
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800518 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800519 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530520 // Byte 2&3, Only used with selecting BIOS
521 if (countToRead || offset)
522 {
523 return ipmi::responseReqDataLenInvalid();
524 }
525
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800526 constexpr const size_t sdrLen = 2;
527 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
528 return ipmi::responseSuccess(
529 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
530 readBuf});
531 }
532 break;
533
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800534 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800535 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800536 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800537}
538
539ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
540 ipmi_request_t request, ipmi_response_t response,
541 ipmi_data_len_t dataLen, ipmi_context_t context)
542{
543 if (*dataLen != 0)
544 {
Jason M. Bills64796042018-10-03 16:51:55 -0700545 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800546 return IPMI_CC_REQ_DATA_LEN_INVALID;
547 }
548
549 *dataLen = 1;
550 uint8_t* res = reinterpret_cast<uint8_t*>(response);
551 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
552 // AIC is available so that BIOS will not timeout repeatly which leads to
553 // slow booting.
554 *res = 0; // Byte1=Count of SlotPosition/FruID records.
555 return IPMI_CC_OK;
556}
557
Jason M. Bills64796042018-10-03 16:51:55 -0700558ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
559 ipmi_request_t request,
560 ipmi_response_t response,
561 ipmi_data_len_t dataLen,
562 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800563{
Jason M. Bills64796042018-10-03 16:51:55 -0700564 GetPowerRestoreDelayRes* resp =
565 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
566
567 if (*dataLen != 0)
568 {
569 *dataLen = 0;
570 return IPMI_CC_REQ_DATA_LEN_INVALID;
571 }
572
Vernon Mauery15419dd2019-05-24 09:40:30 -0700573 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700574 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700575 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700576 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700577 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700578 powerRestoreDelayIntf, powerRestoreDelayProp);
579
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700580 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700581 resp->byteLSB = delay;
582 resp->byteMSB = delay >> 8;
583
584 *dataLen = sizeof(GetPowerRestoreDelayRes);
585
586 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800587}
588
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800589static uint8_t bcdToDec(uint8_t val)
590{
591 return ((val / 16 * 10) + (val % 16));
592}
593
594// Allows an update utility or system BIOS to send the status of an embedded
595// firmware update attempt to the BMC. After received, BMC will create a logging
596// record.
597ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
598 uint8_t majorRevision,
599 uint8_t minorRevision,
600 uint32_t auxInfo)
601{
602 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700603 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800604 target = (target & selEvtTargetMask) >> selEvtTargetShift;
605
606 /* make sure the status is 0, 1, or 2 as per the spec */
607 if (status > 2)
608 {
609 return ipmi::response(ipmi::ccInvalidFieldRequest);
610 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700611 /* make sure the target is 0, 1, 2, or 4 as per the spec */
612 if (target > 4 || target == 3)
613 {
614 return ipmi::response(ipmi::ccInvalidFieldRequest);
615 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800616 /*orignal OEM command is to record OEM SEL.
617 But openbmc does not support OEM SEL, so we redirect it to redfish event
618 logging. */
619 std::string buildInfo;
620 std::string action;
621 switch (FWUpdateTarget(target))
622 {
623 case FWUpdateTarget::targetBMC:
624 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700625 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800626 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
627 " BuildID: " + std::to_string(auxInfo);
628 buildInfo += std::to_string(auxInfo);
629 break;
630 case FWUpdateTarget::targetBIOS:
631 firmware = "BIOS";
632 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700633 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800634 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
635 " minor: " +
636 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
637 " ReleaseNumber: " + // ASCII encoded
638 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
639 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
640 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
641 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
642 break;
643 case FWUpdateTarget::targetME:
644 firmware = "ME";
645 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700646 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800647 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
648 " minor2: " +
649 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
650 " build1: " +
651 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
652 " build2: " +
653 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
654 break;
655 case FWUpdateTarget::targetOEMEWS:
656 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700657 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800658 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
659 " BuildID: " + std::to_string(auxInfo);
660 break;
661 }
662
Jason M. Billsdc249272019-04-03 09:58:40 -0700663 static const std::string openBMCMessageRegistryVersion("0.1");
664 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
665
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800666 switch (status)
667 {
668 case 0x0:
669 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700670 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800671 break;
672 case 0x1:
673 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700674 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800675 break;
676 case 0x2:
677 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700678 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800679 break;
680 default:
681 action = "unknown";
682 break;
683 }
684
Jason M. Billsdc249272019-04-03 09:58:40 -0700685 std::string firmwareInstanceStr =
686 firmware + " instance: " + std::to_string(instance);
687 std::string message("[firmware update] " + firmwareInstanceStr +
688 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800689
690 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700691 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
692 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
693 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800694 return ipmi::responseSuccess();
695}
696
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530697ipmi::RspType<uint8_t, std::vector<uint8_t>>
698 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
699 uint2_t slotNumber, uint3_t baseBoardSlotNum,
700 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
701 uint8_t netFn, uint8_t cmd,
702 std::optional<std::vector<uint8_t>> writeData)
703{
704 if (reserved1 || reserved2)
705 {
706 return ipmi::responseInvalidFieldRequest();
707 }
708
709 boost::system::error_code ec;
710 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
711 std::vector<uint8_t>>;
712 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
713 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
714 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
715 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
716 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
717 *writeData);
718 if (ec)
719 {
720 phosphor::logging::log<phosphor::logging::level::ERR>(
721 "Failed to call dbus method SlotIpmbRequest");
722 return ipmi::responseUnspecifiedError();
723 }
724
725 std::vector<uint8_t> dataReceived(0);
726 int status = -1;
727 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
728
729 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
730
731 if (status)
732 {
733 phosphor::logging::log<phosphor::logging::level::ERR>(
734 "Failed to get response from SlotIpmbRequest");
735 return ipmi::responseResponseError();
736 }
737 return ipmi::responseSuccess(cc, dataReceived);
738}
739
Jason M. Bills64796042018-10-03 16:51:55 -0700740ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
741 ipmi_request_t request,
742 ipmi_response_t response,
743 ipmi_data_len_t dataLen,
744 ipmi_context_t context)
745{
746 SetPowerRestoreDelayReq* data =
747 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
748 uint16_t delay = 0;
749
750 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
751 {
752 *dataLen = 0;
753 return IPMI_CC_REQ_DATA_LEN_INVALID;
754 }
755 delay = data->byteMSB;
756 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700757 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700758 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700759 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
760 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700761 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
762 *dataLen = 0;
763
764 return IPMI_CC_OK;
765}
766
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700767static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700768{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700769 static constexpr const char* cpuPresencePathPrefix =
770 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
771 static constexpr const char* cpuPresenceIntf =
772 "xyz.openbmc_project.Inventory.Item";
773 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
774 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
775 try
Jason M. Bills64796042018-10-03 16:51:55 -0700776 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700777 auto service =
778 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
779
780 ipmi::Value result = ipmi::getDbusProperty(
781 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
782 return std::get<bool>(result);
783 }
784 catch (const std::exception& e)
785 {
786 phosphor::logging::log<phosphor::logging::level::INFO>(
787 "Cannot find processor presence",
788 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
789 return false;
790 }
791}
792
793ipmi::RspType<bool, // CATERR Reset Enabled
794 bool, // ERR2 Reset Enabled
795 uint6_t, // reserved
796 uint8_t, // reserved, returns 0x3F
797 uint6_t, // CPU1 CATERR Count
798 uint2_t, // CPU1 Status
799 uint6_t, // CPU2 CATERR Count
800 uint2_t, // CPU2 Status
801 uint6_t, // CPU3 CATERR Count
802 uint2_t, // CPU3 Status
803 uint6_t, // CPU4 CATERR Count
804 uint2_t, // CPU4 Status
805 uint8_t // Crashdump Count
806 >
807 ipmiOEMGetProcessorErrConfig()
808{
809 bool resetOnCATERR = false;
810 bool resetOnERR2 = false;
811 uint6_t cpu1CATERRCount = 0;
812 uint6_t cpu2CATERRCount = 0;
813 uint6_t cpu3CATERRCount = 0;
814 uint6_t cpu4CATERRCount = 0;
815 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700816 uint2_t cpu1Status = cpuPresent("CPU_1")
817 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
818 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
819 uint2_t cpu2Status = cpuPresent("CPU_2")
820 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
821 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
822 uint2_t cpu3Status = cpuPresent("CPU_3")
823 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
824 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
825 uint2_t cpu4Status = cpuPresent("CPU_4")
826 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
827 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700828
829 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
830 try
831 {
832 auto service = ipmi::getService(*busp, processorErrConfigIntf,
833 processorErrConfigObjPath);
834
835 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
836 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
837 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
838 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
839 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
840 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
841 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
842 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
843 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
844 }
845 catch (const std::exception& e)
846 {
847 phosphor::logging::log<phosphor::logging::level::ERR>(
848 "Failed to fetch processor error config",
849 phosphor::logging::entry("ERROR=%s", e.what()));
850 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700851 }
852
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700853 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
854 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
855 cpu2Status, cpu3CATERRCount, cpu3Status,
856 cpu4CATERRCount, cpu4Status, crashdumpCount);
857}
Jason M. Bills64796042018-10-03 16:51:55 -0700858
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700859ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
860 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
861 std::optional<bool> clearCPUErrorCount,
862 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
863{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000864 if (reserved1 || reserved2)
865 {
866 return ipmi::responseInvalidFieldRequest();
867 }
868
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700869 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700870
871 try
872 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000873 if (reserved3.value_or(0))
874 {
875 return ipmi::responseInvalidFieldRequest();
876 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700877 auto service = ipmi::getService(*busp, processorErrConfigIntf,
878 processorErrConfigObjPath);
879 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
880 processorErrConfigIntf, "ResetOnCATERR",
881 resetOnCATERR);
882 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
883 processorErrConfigIntf, "ResetOnERR2",
884 resetOnERR2);
885 if (clearCPUErrorCount.value_or(false))
886 {
887 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700888 processorErrConfigIntf, "ErrorCountCPU1",
889 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700890 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700891 processorErrConfigIntf, "ErrorCountCPU2",
892 static_cast<uint8_t>(0));
893 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
894 processorErrConfigIntf, "ErrorCountCPU3",
895 static_cast<uint8_t>(0));
896 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
897 processorErrConfigIntf, "ErrorCountCPU4",
898 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700899 }
900 if (clearCrashdumpCount.value_or(false))
901 {
902 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700903 processorErrConfigIntf, "CrashdumpCount",
904 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700905 }
Jason M. Bills64796042018-10-03 16:51:55 -0700906 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500907 catch (const std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700908 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800909 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700910 "Failed to set processor error config",
911 phosphor::logging::entry("EXCEPTION=%s", e.what()));
912 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700913 }
914
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700915 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700916}
917
Yong Li703922d2018-11-06 13:25:31 +0800918ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
919 ipmi_request_t request,
920 ipmi_response_t response,
921 ipmi_data_len_t dataLen,
922 ipmi_context_t context)
923{
924 GetOEMShutdownPolicyRes* resp =
925 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
926
927 if (*dataLen != 0)
928 {
929 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800930 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800931 *dataLen = 0;
932 return IPMI_CC_REQ_DATA_LEN_INVALID;
933 }
934
935 *dataLen = 0;
936
937 try
938 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700939 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800940 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700941 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
942 Value variant = getDbusProperty(
943 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
944 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800945
946 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
947 convertPolicyFromString(std::get<std::string>(variant)) ==
948 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
949 NoShutdownOnOCOT)
950 {
951 resp->policy = 0;
952 }
953 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
954 convertPolicyFromString(std::get<std::string>(variant)) ==
955 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
956 Policy::ShutdownOnOCOT)
957 {
958 resp->policy = 1;
959 }
960 else
961 {
962 phosphor::logging::log<phosphor::logging::level::ERR>(
963 "oem_set_shutdown_policy: invalid property!",
964 phosphor::logging::entry(
965 "PROP=%s", std::get<std::string>(variant).c_str()));
966 return IPMI_CC_UNSPECIFIED_ERROR;
967 }
Yong Li703922d2018-11-06 13:25:31 +0800968 // TODO needs to check if it is multi-node products,
969 // policy is only supported on node 3/4
970 resp->policySupport = shutdownPolicySupported;
971 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500972 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +0800973 {
974 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
975 return IPMI_CC_UNSPECIFIED_ERROR;
976 }
977
978 *dataLen = sizeof(GetOEMShutdownPolicyRes);
979 return IPMI_CC_OK;
980}
981
982ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
983 ipmi_request_t request,
984 ipmi_response_t response,
985 ipmi_data_len_t dataLen,
986 ipmi_context_t context)
987{
988 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800989 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
990 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
991 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800992
993 // TODO needs to check if it is multi-node products,
994 // policy is only supported on node 3/4
995 if (*dataLen != 1)
996 {
997 phosphor::logging::log<phosphor::logging::level::ERR>(
998 "oem_set_shutdown_policy: invalid input len!");
999 *dataLen = 0;
1000 return IPMI_CC_REQ_DATA_LEN_INVALID;
1001 }
1002
1003 *dataLen = 0;
1004 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
1005 {
1006 phosphor::logging::log<phosphor::logging::level::ERR>(
1007 "oem_set_shutdown_policy: invalid input!");
1008 return IPMI_CC_INVALID_FIELD_REQUEST;
1009 }
1010
Yong Li0669d192019-05-06 14:01:46 +08001011 if (*req == noShutdownOnOCOT)
1012 {
1013 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1014 Policy::NoShutdownOnOCOT;
1015 }
1016 else
1017 {
1018 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1019 Policy::ShutdownOnOCOT;
1020 }
1021
Yong Li703922d2018-11-06 13:25:31 +08001022 try
1023 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001024 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +08001025 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001026 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +08001027 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001028 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +08001029 oemShutdownPolicyObjPathProp,
1030 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +08001031 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001032 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1035 return IPMI_CC_UNSPECIFIED_ERROR;
1036 }
1037
1038 return IPMI_CC_OK;
1039}
1040
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301041/** @brief implementation for check the DHCP or not in IPv4
1042 * @param[in] Channel - Channel number
1043 * @returns true or false.
1044 */
1045static bool isDHCPEnabled(uint8_t Channel)
1046{
1047 try
1048 {
1049 auto ethdevice = getChannelName(Channel);
1050 if (ethdevice.empty())
1051 {
1052 return false;
1053 }
1054 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001055 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301056 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001057 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1058 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301059 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001060 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301061 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1062 {
1063 return true;
1064 }
1065 else
1066 {
1067 return false;
1068 }
1069 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001070 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301071 {
1072 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1073 return true;
1074 }
1075}
1076
1077/** @brief implementes for check the DHCP or not in IPv6
1078 * @param[in] Channel - Channel number
1079 * @returns true or false.
1080 */
1081static bool isDHCPIPv6Enabled(uint8_t Channel)
1082{
1083
1084 try
1085 {
1086 auto ethdevice = getChannelName(Channel);
1087 if (ethdevice.empty())
1088 {
1089 return false;
1090 }
1091 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001092 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301093 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001094 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1095 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301096 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001097 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301098 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1099 {
1100 return true;
1101 }
1102 else
1103 {
1104 return false;
1105 }
1106 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001107 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301108 {
1109 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1110 return true;
1111 }
1112}
1113
1114/** @brief implementes the creating of default new user
1115 * @param[in] userName - new username in 16 bytes.
1116 * @param[in] userPassword - new password in 20 bytes
1117 * @returns ipmi completion code.
1118 */
1119ipmi::RspType<> ipmiOEMSetUser2Activation(
1120 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001121 const SecureBuffer& userPassword)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301122{
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001123 if (userPassword.size() != ipmi::maxIpmi20PasswordSize)
1124 {
1125 return ipmi::responseReqDataLenInvalid();
1126 }
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301127 bool userState = false;
1128 // Check for System Interface not exist and LAN should be static
1129 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1130 {
Manish Baing440f62b2021-07-15 22:00:37 +00001131 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301132 try
1133 {
1134 getChannelInfo(channel, chInfo);
1135 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001136 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301137 {
1138 phosphor::logging::log<phosphor::logging::level::ERR>(
1139 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1140 phosphor::logging::entry("MSG: %s", e.description()));
1141 return ipmi::response(ipmi::ccUnspecifiedError);
1142 }
1143 if (chInfo.mediumType ==
1144 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1145 {
1146 phosphor::logging::log<phosphor::logging::level::ERR>(
1147 "ipmiOEMSetUser2Activation: system interface exist .");
1148 return ipmi::response(ipmi::ccCommandNotAvailable);
1149 }
1150 else
1151 {
1152
1153 if (chInfo.mediumType ==
1154 static_cast<uint8_t>(EChannelMediumType::lan8032))
1155 {
1156 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1157 {
1158 phosphor::logging::log<phosphor::logging::level::ERR>(
1159 "ipmiOEMSetUser2Activation: DHCP enabled .");
1160 return ipmi::response(ipmi::ccCommandNotAvailable);
1161 }
1162 }
1163 }
1164 }
1165 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1166 if (ipmi::ccSuccess ==
1167 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1168 {
1169 if (enabledUsers > 1)
1170 {
1171 phosphor::logging::log<phosphor::logging::level::ERR>(
1172 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1173 return ipmi::response(ipmi::ccCommandNotAvailable);
1174 }
1175 // Check the user 2 is enabled or not
1176 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1177 if (userState == true)
1178 {
1179 phosphor::logging::log<phosphor::logging::level::ERR>(
1180 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1181 return ipmi::response(ipmi::ccCommandNotAvailable);
1182 }
1183 }
1184 else
1185 {
1186 return ipmi::response(ipmi::ccUnspecifiedError);
1187 }
1188
1189#if BYTE_ORDER == LITTLE_ENDIAN
1190 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1191#endif
1192#if BYTE_ORDER == BIG_ENDIAN
1193 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1194#endif
1195
Vernon Mauery037cabd2020-05-14 12:16:01 -07001196 // ipmiUserSetUserName correctly handles char*, possibly non-null
1197 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001198 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1199 sizeof(userName));
1200 const std::string userNameRaw(
1201 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001202
Vernon Mauery037cabd2020-05-14 12:16:01 -07001203 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301204 {
1205 if (ipmi::ccSuccess ==
1206 ipmiUserSetUserPassword(
1207 ipmiDefaultUserId,
1208 reinterpret_cast<const char*>(userPassword.data())))
1209 {
1210 if (ipmi::ccSuccess ==
1211 ipmiUserSetPrivilegeAccess(
1212 ipmiDefaultUserId,
1213 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1214 privAccess, true))
1215 {
1216 phosphor::logging::log<phosphor::logging::level::INFO>(
1217 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001218
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301219 return ipmi::responseSuccess();
1220 }
1221 }
1222 // we need to delete the default user id which added in this command as
1223 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001224 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301225 phosphor::logging::log<phosphor::logging::level::ERR>(
1226 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1227 }
1228 else
1229 {
1230 phosphor::logging::log<phosphor::logging::level::ERR>(
1231 "ipmiOEMSetUser2Activation: Setting username failed.");
1232 }
1233
1234 return ipmi::response(ipmi::ccCommandNotAvailable);
1235}
1236
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301237/** @brief implementes executing the linux command
1238 * @param[in] linux command
1239 * @returns status
1240 */
1241
1242static uint8_t executeCmd(const char* path)
1243{
1244 boost::process::child execProg(path);
1245 execProg.wait();
1246
1247 int retCode = execProg.exit_code();
1248 if (retCode)
1249 {
1250 return ipmi::ccUnspecifiedError;
1251 }
1252 return ipmi::ccSuccess;
1253}
1254
1255/** @brief implementes ASD Security event logging
1256 * @param[in] Event message string
1257 * @param[in] Event Severity
1258 * @returns status
1259 */
1260
1261static void atScaleDebugEventlog(std::string msg, int severity)
1262{
1263 std::string eventStr = "OpenBMC.0.1." + msg;
1264 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1265 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1266 eventStr.c_str(), NULL);
1267}
1268
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301269/** @brief implementes setting password for special user
1270 * @param[in] specialUserIndex
1271 * @param[in] userPassword - new password in 20 bytes
1272 * @returns ipmi completion code.
1273 */
1274ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1275 uint8_t specialUserIndex,
1276 std::vector<uint8_t> userPassword)
1277{
1278 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301279 ipmi_ret_t status = ipmi::ccSuccess;
1280
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301281 try
1282 {
1283 getChannelInfo(ctx->channel, chInfo);
1284 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001285 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301286 {
1287 phosphor::logging::log<phosphor::logging::level::ERR>(
1288 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1289 phosphor::logging::entry("MSG: %s", e.description()));
1290 return ipmi::responseUnspecifiedError();
1291 }
1292 if (chInfo.mediumType !=
1293 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1294 {
1295 phosphor::logging::log<phosphor::logging::level::ERR>(
1296 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1297 "interface");
1298 return ipmi::responseCommandNotAvailable();
1299 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301300
1301 // 0 for root user and 1 for AtScaleDebug is allowed
1302 if (specialUserIndex >
1303 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301304 {
1305 phosphor::logging::log<phosphor::logging::level::ERR>(
1306 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1307 return ipmi::responseParmOutOfRange();
1308 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301309 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301310 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301311 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001312 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301313 if (userPassword.size() < minPasswordSizeRequired ||
1314 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1315 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001316 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301317 return ipmi::responseReqDataLenInvalid();
1318 }
1319 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1320 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001321 // Clear sensitive data
1322 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301323 if (specialUserIndex ==
1324 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1325 {
1326 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1327
1328 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1329 }
1330 else
1331 {
1332 status = ipmiSetSpecialUserPassword("root", passwd);
1333 }
1334 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301335 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301336 else
1337 {
1338 if (specialUserIndex ==
1339 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1340 {
1341 status = executeCmd("passwd -d root");
1342 }
1343 else
1344 {
1345
1346 status = executeCmd("passwd -d asdbg");
1347
1348 if (status == 0)
1349 {
1350 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1351 LOG_INFO);
1352 }
1353 }
1354 return ipmi::response(status);
1355 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301356}
1357
Kuiying Wang45f04982018-12-26 09:23:08 +08001358namespace ledAction
1359{
1360using namespace sdbusplus::xyz::openbmc_project::Led::server;
1361std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001362 {Physical::Action::Off, 0},
1363 {Physical::Action::On, 2},
1364 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001365
1366std::map<uint8_t, std::string> offsetObjPath = {
1367 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1368
1369} // namespace ledAction
1370
1371int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1372 const std::string& objPath, uint8_t& state)
1373{
1374 try
1375 {
1376 std::string service = getService(bus, intf, objPath);
1377 Value stateValue =
1378 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001379 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001380 state = ledAction::actionDbusToIpmi.at(
1381 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1382 convertActionFromString(strState));
1383 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001384 catch (const sdbusplus::exception::exception& e)
Kuiying Wang45f04982018-12-26 09:23:08 +08001385 {
1386 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1387 return -1;
1388 }
1389 return 0;
1390}
1391
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001392ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001393{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001394 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001395 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001396 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001397 for (auto it = ledAction::offsetObjPath.begin();
1398 it != ledAction::offsetObjPath.end(); ++it)
1399 {
1400 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001401 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001402 {
1403 phosphor::logging::log<phosphor::logging::level::ERR>(
1404 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001405 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001406 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001407 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001408 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001409 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001410}
1411
Yong Li23737fe2019-02-19 08:49:55 +08001412ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1413 ipmi_request_t request,
1414 ipmi_response_t response,
1415 ipmi_data_len_t dataLen,
1416 ipmi_context_t context)
1417{
1418 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1419 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1420
1421 if (*dataLen == 0)
1422 {
1423 phosphor::logging::log<phosphor::logging::level::ERR>(
1424 "CfgHostSerial: invalid input len!",
1425 phosphor::logging::entry("LEN=%d", *dataLen));
1426 return IPMI_CC_REQ_DATA_LEN_INVALID;
1427 }
1428
1429 switch (req->command)
1430 {
1431 case getHostSerialCfgCmd:
1432 {
1433 if (*dataLen != 1)
1434 {
1435 phosphor::logging::log<phosphor::logging::level::ERR>(
1436 "CfgHostSerial: invalid input len!");
1437 *dataLen = 0;
1438 return IPMI_CC_REQ_DATA_LEN_INVALID;
1439 }
1440
1441 *dataLen = 0;
1442
1443 boost::process::ipstream is;
1444 std::vector<std::string> data;
1445 std::string line;
1446 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1447 boost::process::std_out > is);
1448
1449 while (c1.running() && std::getline(is, line) && !line.empty())
1450 {
1451 data.push_back(line);
1452 }
1453
1454 c1.wait();
1455 if (c1.exit_code())
1456 {
1457 phosphor::logging::log<phosphor::logging::level::ERR>(
1458 "CfgHostSerial:: error on execute",
1459 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1460 // Using the default value
1461 *resp = 0;
1462 }
1463 else
1464 {
1465 if (data.size() != 1)
1466 {
1467 phosphor::logging::log<phosphor::logging::level::ERR>(
1468 "CfgHostSerial:: error on read env");
1469 return IPMI_CC_UNSPECIFIED_ERROR;
1470 }
1471 try
1472 {
1473 unsigned long tmp = std::stoul(data[0]);
1474 if (tmp > std::numeric_limits<uint8_t>::max())
1475 {
1476 throw std::out_of_range("Out of range");
1477 }
1478 *resp = static_cast<uint8_t>(tmp);
1479 }
1480 catch (const std::invalid_argument& e)
1481 {
1482 phosphor::logging::log<phosphor::logging::level::ERR>(
1483 "invalid config ",
1484 phosphor::logging::entry("ERR=%s", e.what()));
1485 return IPMI_CC_UNSPECIFIED_ERROR;
1486 }
1487 catch (const std::out_of_range& e)
1488 {
1489 phosphor::logging::log<phosphor::logging::level::ERR>(
1490 "out_of_range config ",
1491 phosphor::logging::entry("ERR=%s", e.what()));
1492 return IPMI_CC_UNSPECIFIED_ERROR;
1493 }
1494 }
1495
1496 *dataLen = 1;
1497 break;
1498 }
1499 case setHostSerialCfgCmd:
1500 {
1501 if (*dataLen != sizeof(CfgHostSerialReq))
1502 {
1503 phosphor::logging::log<phosphor::logging::level::ERR>(
1504 "CfgHostSerial: invalid input len!");
1505 *dataLen = 0;
1506 return IPMI_CC_REQ_DATA_LEN_INVALID;
1507 }
1508
1509 *dataLen = 0;
1510
1511 if (req->parameter > HostSerialCfgParamMax)
1512 {
1513 phosphor::logging::log<phosphor::logging::level::ERR>(
1514 "CfgHostSerial: invalid input!");
1515 return IPMI_CC_INVALID_FIELD_REQUEST;
1516 }
1517
1518 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1519 std::to_string(req->parameter));
1520
1521 c1.wait();
1522 if (c1.exit_code())
1523 {
1524 phosphor::logging::log<phosphor::logging::level::ERR>(
1525 "CfgHostSerial:: error on execute",
1526 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1527 return IPMI_CC_UNSPECIFIED_ERROR;
1528 }
1529 break;
1530 }
1531 default:
1532 phosphor::logging::log<phosphor::logging::level::ERR>(
1533 "CfgHostSerial: invalid input!");
1534 *dataLen = 0;
1535 return IPMI_CC_INVALID_FIELD_REQUEST;
1536 }
1537
1538 return IPMI_CC_OK;
1539}
1540
James Feist91244a62019-02-19 15:04:54 -08001541constexpr const char* thermalModeInterface =
1542 "xyz.openbmc_project.Control.ThermalMode";
1543constexpr const char* thermalModePath =
1544 "/xyz/openbmc_project/control/thermal_mode";
1545
1546bool getFanProfileInterface(
1547 sdbusplus::bus::bus& bus,
1548 boost::container::flat_map<
1549 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1550{
1551 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1552 "GetAll");
1553 call.append(thermalModeInterface);
1554 try
1555 {
1556 auto data = bus.call(call);
1557 data.read(resp);
1558 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001559 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001560 {
1561 phosphor::logging::log<phosphor::logging::level::ERR>(
1562 "getFanProfileInterface: can't get thermal mode!",
1563 phosphor::logging::entry("ERR=%s", e.what()));
1564 return false;
1565 }
1566 return true;
1567}
1568
anil kumar appanaf945eee2019-09-25 23:29:11 +00001569/**@brief implements the OEM set fan config.
1570 * @param selectedFanProfile - fan profile to enable
1571 * @param reserved1
1572 * @param performanceMode - Performance/Acoustic mode
1573 * @param reserved2
1574 * @param setPerformanceMode - set Performance/Acoustic mode
1575 * @param setFanProfile - set fan profile
1576 *
1577 * @return IPMI completion code.
1578 **/
1579ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1580
1581 uint2_t reserved1, bool performanceMode,
1582 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301583 bool setFanProfile,
1584 std::optional<uint8_t> dimmGroupId,
1585 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001586{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001587 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001588 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001589 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001590 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301591
1592 if (dimmGroupId)
1593 {
1594 if (*dimmGroupId >= maxCPUNum)
1595 {
1596 return ipmi::responseInvalidFieldRequest();
1597 }
1598 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1599 {
1600 return ipmi::responseInvalidFieldRequest();
1601 }
1602 }
1603
James Feist91244a62019-02-19 15:04:54 -08001604 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001605 boost::container::flat_map<
1606 std::string, std::variant<std::vector<std::string>, std::string>>
1607 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001608 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1609 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001610 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001611 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001612 }
1613
1614 std::vector<std::string>* supported =
1615 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1616 if (supported == nullptr)
1617 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001618 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001619 }
1620 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001621 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001622 {
James Feist91244a62019-02-19 15:04:54 -08001623 if (performanceMode)
1624 {
1625
1626 if (std::find(supported->begin(), supported->end(),
1627 "Performance") != supported->end())
1628 {
1629 mode = "Performance";
1630 }
1631 }
1632 else
1633 {
James Feist91244a62019-02-19 15:04:54 -08001634 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1635 supported->end())
1636 {
1637 mode = "Acoustic";
1638 }
1639 }
1640 if (mode.empty())
1641 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001642 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001643 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001644
1645 try
1646 {
1647 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1648 thermalModeInterface, "Current", mode);
1649 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001650 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001651 {
1652 phosphor::logging::log<phosphor::logging::level::ERR>(
1653 "ipmiOEMSetFanConfig: can't set thermal mode!",
1654 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1655 return ipmi::responseResponseError();
1656 }
James Feist91244a62019-02-19 15:04:54 -08001657 }
1658
anil kumar appanaf945eee2019-09-25 23:29:11 +00001659 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001660}
1661
James Feist5b693632019-07-09 09:06:09 -07001662ipmi::RspType<uint8_t, // profile support map
1663 uint8_t, // fan control profile enable
1664 uint8_t, // flags
1665 uint32_t // dimm presence bit map
1666 >
1667 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001668{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301669 if (dimmGroupId >= maxCPUNum)
1670 {
1671 return ipmi::responseInvalidFieldRequest();
1672 }
1673
1674 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1675
1676 if (!cpuStatus)
1677 {
1678 return ipmi::responseInvalidFieldRequest();
1679 }
1680
James Feist91244a62019-02-19 15:04:54 -08001681 boost::container::flat_map<
1682 std::string, std::variant<std::vector<std::string>, std::string>>
1683 profileData;
1684
Vernon Mauery15419dd2019-05-24 09:40:30 -07001685 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1686 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001687 {
James Feist5b693632019-07-09 09:06:09 -07001688 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001689 }
1690
1691 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1692
1693 if (current == nullptr)
1694 {
1695 phosphor::logging::log<phosphor::logging::level::ERR>(
1696 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001697 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001698 }
1699 bool performance = (*current == "Performance");
1700
James Feist5b693632019-07-09 09:06:09 -07001701 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001702 if (performance)
1703 {
James Feist5b693632019-07-09 09:06:09 -07001704 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001705 }
1706
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001707 constexpr uint8_t fanControlDefaultProfile = 0x80;
1708 constexpr uint8_t fanControlProfileState = 0x00;
1709 constexpr uint32_t dimmPresenceBitmap = 0x00;
1710
1711 return ipmi::responseSuccess(fanControlDefaultProfile,
1712 fanControlProfileState, flags,
1713 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001714}
James Feist5f957ca2019-03-14 15:33:55 -07001715constexpr const char* cfmLimitSettingPath =
1716 "/xyz/openbmc_project/control/cfm_limit";
1717constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001718constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001719constexpr const size_t legacyPCHSensorNumber = 0x22;
1720constexpr const char* exitAirPathName = "Exit_Air";
1721constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001722constexpr const char* pidConfigurationIface =
1723 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001724
James Feist09f6b602019-08-08 11:30:03 -07001725static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001726{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001727 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001728 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001729 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1730 "/xyz/openbmc_project/object_mapper",
1731 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001732
James Feistacc8a4e2019-04-02 14:23:57 -07001733 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001734 std::string path;
1735 GetSubTreeType resp;
1736 try
1737 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001738 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001739 reply.read(resp);
1740 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001741 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001742 {
1743 phosphor::logging::log<phosphor::logging::level::ERR>(
1744 "ipmiOEMGetFscParameter: mapper error");
1745 };
James Feist09f6b602019-08-08 11:30:03 -07001746 auto config =
1747 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1748 return pair.first.find(name) != std::string::npos;
1749 });
James Feistfaa4f222019-03-21 16:21:55 -07001750 if (config != resp.end())
1751 {
1752 path = std::move(config->first);
1753 }
1754 return path;
1755}
James Feist5f957ca2019-03-14 15:33:55 -07001756
James Feistacc8a4e2019-04-02 14:23:57 -07001757// flat map to make alphabetical
1758static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1759{
1760 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001761 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001762 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001763 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1764 "/xyz/openbmc_project/object_mapper",
1765 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001766
1767 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1768 GetSubTreeType resp;
1769
1770 try
1771 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001772 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001773 reply.read(resp);
1774 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001775 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001776 {
1777 phosphor::logging::log<phosphor::logging::level::ERR>(
1778 "getFanConfigPaths: mapper error");
1779 };
1780 for (const auto& [path, objects] : resp)
1781 {
1782 if (objects.empty())
1783 {
1784 continue; // should be impossible
1785 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001786
1787 try
1788 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001789 ret.emplace(path,
1790 getAllDbusProperties(*dbus, objects[0].first, path,
1791 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001792 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001793 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001794 {
1795 phosphor::logging::log<phosphor::logging::level::ERR>(
1796 "getPidConfigs: can't get DbusProperties!",
1797 phosphor::logging::entry("ERR=%s", e.what()));
1798 }
James Feistacc8a4e2019-04-02 14:23:57 -07001799 }
1800 return ret;
1801}
1802
1803ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1804{
1805 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1806 if (data.empty())
1807 {
1808 return ipmi::responseResponseError();
1809 }
1810 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1811 for (const auto& [_, pid] : data)
1812 {
1813 auto findClass = pid.find("Class");
1814 if (findClass == pid.end())
1815 {
1816 phosphor::logging::log<phosphor::logging::level::ERR>(
1817 "ipmiOEMGetFscParameter: found illegal pid "
1818 "configurations");
1819 return ipmi::responseResponseError();
1820 }
1821 std::string type = std::get<std::string>(findClass->second);
1822 if (type == "fan")
1823 {
1824 auto findOutLimit = pid.find("OutLimitMin");
1825 if (findOutLimit == pid.end())
1826 {
1827 phosphor::logging::log<phosphor::logging::level::ERR>(
1828 "ipmiOEMGetFscParameter: found illegal pid "
1829 "configurations");
1830 return ipmi::responseResponseError();
1831 }
1832 // get the min out of all the offsets
1833 minOffset = std::min(
1834 minOffset,
1835 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1836 }
1837 }
1838 if (minOffset == std::numeric_limits<uint8_t>::max())
1839 {
1840 phosphor::logging::log<phosphor::logging::level::ERR>(
1841 "ipmiOEMGetFscParameter: found no fan configurations!");
1842 return ipmi::responseResponseError();
1843 }
1844
1845 return ipmi::responseSuccess(minOffset);
1846}
1847
1848ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1849{
Manish Baingbaa579f2021-10-08 22:30:32 +00001850 constexpr uint8_t maxFanSpeedOffset = 100;
1851 if (offset > maxFanSpeedOffset)
1852 {
1853 phosphor::logging::log<phosphor::logging::level::ERR>(
1854 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1855 return ipmi::responseInvalidFieldRequest();
1856 }
James Feistacc8a4e2019-04-02 14:23:57 -07001857 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1858 if (data.empty())
1859 {
1860
1861 phosphor::logging::log<phosphor::logging::level::ERR>(
1862 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1863 return ipmi::responseResponseError();
1864 }
1865
Vernon Mauery15419dd2019-05-24 09:40:30 -07001866 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001867 bool found = false;
1868 for (const auto& [path, pid] : data)
1869 {
1870 auto findClass = pid.find("Class");
1871 if (findClass == pid.end())
1872 {
1873
1874 phosphor::logging::log<phosphor::logging::level::ERR>(
1875 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1876 "configurations");
1877 return ipmi::responseResponseError();
1878 }
1879 std::string type = std::get<std::string>(findClass->second);
1880 if (type == "fan")
1881 {
1882 auto findOutLimit = pid.find("OutLimitMin");
1883 if (findOutLimit == pid.end())
1884 {
1885
1886 phosphor::logging::log<phosphor::logging::level::ERR>(
1887 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1888 "configurations");
1889 return ipmi::responseResponseError();
1890 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001891 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001892 path, pidConfigurationIface, "OutLimitMin",
1893 static_cast<double>(offset));
1894 found = true;
1895 }
1896 }
1897 if (!found)
1898 {
1899 phosphor::logging::log<phosphor::logging::level::ERR>(
1900 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1901 return ipmi::responseResponseError();
1902 }
1903
1904 return ipmi::responseSuccess();
1905}
1906
1907ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1908 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001909{
1910 constexpr const size_t disableLimiting = 0x0;
1911
Vernon Mauery15419dd2019-05-24 09:40:30 -07001912 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001913 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001914 {
James Feist09f6b602019-08-08 11:30:03 -07001915 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001916 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001917 {
James Feist09f6b602019-08-08 11:30:03 -07001918 pathName = exitAirPathName;
1919 }
1920 else if (param1 == legacyPCHSensorNumber)
1921 {
1922 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001923 }
1924 else
1925 {
James Feistacc8a4e2019-04-02 14:23:57 -07001926 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001927 }
James Feist09f6b602019-08-08 11:30:03 -07001928 std::string path = getConfigPath(pathName);
1929 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1930 pidConfigurationIface, "SetPoint",
1931 static_cast<double>(param2));
1932 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001933 }
James Feistacc8a4e2019-04-02 14:23:57 -07001934 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001935 {
James Feistacc8a4e2019-04-02 14:23:57 -07001936 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001937
1938 // must be greater than 50 based on eps
1939 if (cfm < 50 && cfm != disableLimiting)
1940 {
James Feistacc8a4e2019-04-02 14:23:57 -07001941 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001942 }
1943
1944 try
1945 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001946 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001947 cfmLimitIface, "Limit",
1948 static_cast<double>(cfm));
1949 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001950 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07001951 {
1952 phosphor::logging::log<phosphor::logging::level::ERR>(
1953 "ipmiOEMSetFscParameter: can't set cfm setting!",
1954 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001955 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001956 }
James Feistacc8a4e2019-04-02 14:23:57 -07001957 return ipmi::responseSuccess();
1958 }
1959 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1960 {
1961 constexpr const size_t maxDomainCount = 8;
1962 uint8_t requestedDomainMask = param1;
1963 boost::container::flat_map data = getPidConfigs();
1964 if (data.empty())
1965 {
1966
1967 phosphor::logging::log<phosphor::logging::level::ERR>(
1968 "ipmiOEMSetFscParameter: found no pid configurations!");
1969 return ipmi::responseResponseError();
1970 }
1971 size_t count = 0;
1972 for (const auto& [path, pid] : data)
1973 {
1974 auto findClass = pid.find("Class");
1975 if (findClass == pid.end())
1976 {
1977
1978 phosphor::logging::log<phosphor::logging::level::ERR>(
1979 "ipmiOEMSetFscParameter: found illegal pid "
1980 "configurations");
1981 return ipmi::responseResponseError();
1982 }
1983 std::string type = std::get<std::string>(findClass->second);
1984 if (type == "fan")
1985 {
1986 if (requestedDomainMask & (1 << count))
1987 {
1988 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001989 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001990 pidConfigurationIface, "OutLimitMax",
1991 static_cast<double>(param2));
1992 }
1993 count++;
1994 }
1995 }
1996 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001997 }
1998 else
1999 {
2000 // todo other command parts possibly
2001 // tcontrol is handled in peci now
2002 // fan speed offset not implemented yet
2003 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002004 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002005 }
2006}
2007
James Feistacc8a4e2019-04-02 14:23:57 -07002008ipmi::RspType<
2009 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2010 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002011{
James Feist09f6b602019-08-08 11:30:03 -07002012 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002013
Vernon Mauery15419dd2019-05-24 09:40:30 -07002014 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002015 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002016 {
James Feistacc8a4e2019-04-02 14:23:57 -07002017 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002018 {
James Feistacc8a4e2019-04-02 14:23:57 -07002019 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002020 }
2021
James Feist09f6b602019-08-08 11:30:03 -07002022 std::string pathName;
2023
2024 if (*param == legacyExitAirSensorNumber)
2025 {
2026 pathName = exitAirPathName;
2027 }
2028 else if (*param == legacyPCHSensorNumber)
2029 {
2030 pathName = pchPathName;
2031 }
2032 else
James Feistfaa4f222019-03-21 16:21:55 -07002033 {
James Feistacc8a4e2019-04-02 14:23:57 -07002034 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002035 }
James Feist09f6b602019-08-08 11:30:03 -07002036
2037 uint8_t setpoint = legacyDefaultSetpoint;
2038 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002039 if (path.size())
2040 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002041 Value val = ipmi::getDbusProperty(
2042 *dbus, "xyz.openbmc_project.EntityManager", path,
2043 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002044 setpoint = std::floor(std::get<double>(val) + 0.5);
2045 }
2046
2047 // old implementation used to return the "default" and current, we
2048 // don't make the default readily available so just make both the
2049 // same
James Feistfaa4f222019-03-21 16:21:55 -07002050
James Feistacc8a4e2019-04-02 14:23:57 -07002051 return ipmi::responseSuccess(
2052 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002053 }
James Feistacc8a4e2019-04-02 14:23:57 -07002054 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2055 {
2056 constexpr const size_t maxDomainCount = 8;
2057
2058 if (!param)
2059 {
2060 return ipmi::responseReqDataLenInvalid();
2061 }
2062 uint8_t requestedDomain = *param;
2063 if (requestedDomain >= maxDomainCount)
2064 {
2065 return ipmi::responseInvalidFieldRequest();
2066 }
2067
2068 boost::container::flat_map data = getPidConfigs();
2069 if (data.empty())
2070 {
2071 phosphor::logging::log<phosphor::logging::level::ERR>(
2072 "ipmiOEMGetFscParameter: found no pid configurations!");
2073 return ipmi::responseResponseError();
2074 }
2075 size_t count = 0;
2076 for (const auto& [_, pid] : data)
2077 {
2078 auto findClass = pid.find("Class");
2079 if (findClass == pid.end())
2080 {
2081 phosphor::logging::log<phosphor::logging::level::ERR>(
2082 "ipmiOEMGetFscParameter: found illegal pid "
2083 "configurations");
2084 return ipmi::responseResponseError();
2085 }
2086 std::string type = std::get<std::string>(findClass->second);
2087 if (type == "fan")
2088 {
2089 if (requestedDomain == count)
2090 {
2091 auto findOutLimit = pid.find("OutLimitMax");
2092 if (findOutLimit == pid.end())
2093 {
2094 phosphor::logging::log<phosphor::logging::level::ERR>(
2095 "ipmiOEMGetFscParameter: found illegal pid "
2096 "configurations");
2097 return ipmi::responseResponseError();
2098 }
2099
2100 return ipmi::responseSuccess(
2101 static_cast<uint8_t>(std::floor(
2102 std::get<double>(findOutLimit->second) + 0.5)));
2103 }
2104 else
2105 {
2106 count++;
2107 }
2108 }
2109 }
2110
2111 return ipmi::responseInvalidFieldRequest();
2112 }
2113 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002114 {
2115
2116 /*
2117 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002118 previous behavior didn't seem to prevent this, ignore the check for
2119 now.
James Feist5f957ca2019-03-14 15:33:55 -07002120
James Feistacc8a4e2019-04-02 14:23:57 -07002121 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002122 {
2123 phosphor::logging::log<phosphor::logging::level::ERR>(
2124 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002125 return IPMI_CC_REQ_DATA_LEN_INVALID;
2126 }
2127 */
2128 Value cfmLimit;
2129 Value cfmMaximum;
2130 try
2131 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002132 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002133 cfmLimitSettingPath, cfmLimitIface,
2134 "Limit");
2135 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002136 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002137 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2138 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002139 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002140 {
2141 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002142 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002143 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002144 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002145 }
2146
James Feistacc8a4e2019-04-02 14:23:57 -07002147 double cfmMax = std::get<double>(cfmMaximum);
2148 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002149
James Feistacc8a4e2019-04-02 14:23:57 -07002150 cfmLim = std::floor(cfmLim + 0.5);
2151 cfmMax = std::floor(cfmMax + 0.5);
2152 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2153 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002154
James Feistacc8a4e2019-04-02 14:23:57 -07002155 return ipmi::responseSuccess(
2156 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002157 }
James Feistacc8a4e2019-04-02 14:23:57 -07002158
James Feist5f957ca2019-03-14 15:33:55 -07002159 else
2160 {
2161 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002162 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002163 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002164 }
2165}
2166
Cheng C Yang773703a2019-08-15 09:41:11 +08002167using crConfigVariant =
2168 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2169
2170int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2171 const crConfigVariant& value,
2172 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2173{
2174 boost::system::error_code ec;
2175 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002176 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002177 "/xyz/openbmc_project/control/power_supply_redundancy",
2178 "org.freedesktop.DBus.Properties", "Set",
2179 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2180 if (ec)
2181 {
2182 phosphor::logging::log<phosphor::logging::level::ERR>(
2183 "Failed to set dbus property to cold redundancy");
2184 return -1;
2185 }
2186
2187 return 0;
2188}
2189
Kuiying Wange45333a2020-07-22 22:06:37 +08002190int getCRConfig(
2191 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2192 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2193 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002194{
2195 boost::system::error_code ec;
2196 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002197 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002198 "/xyz/openbmc_project/control/power_supply_redundancy",
2199 "org.freedesktop.DBus.Properties", "Get",
2200 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2201 if (ec)
2202 {
2203 phosphor::logging::log<phosphor::logging::level::ERR>(
2204 "Failed to get dbus property to cold redundancy");
2205 return -1;
2206 }
2207 return 0;
2208}
2209
2210uint8_t getPSUCount(void)
2211{
2212 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2213 ipmi::Value num;
2214 try
2215 {
2216 num = ipmi::getDbusProperty(
2217 *dbus, "xyz.openbmc_project.PSURedundancy",
2218 "/xyz/openbmc_project/control/power_supply_redundancy",
2219 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2220 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002221 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002222 {
2223 phosphor::logging::log<phosphor::logging::level::ERR>(
2224 "Failed to get PSUNumber property from dbus interface");
2225 return 0;
2226 }
2227 uint8_t* pNum = std::get_if<uint8_t>(&num);
2228 if (!pNum)
2229 {
2230 phosphor::logging::log<phosphor::logging::level::ERR>(
2231 "Error to get PSU Number");
2232 return 0;
2233 }
2234 return *pNum;
2235}
2236
2237bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2238{
2239 if (conf.size() < num)
2240 {
2241 phosphor::logging::log<phosphor::logging::level::ERR>(
2242 "Invalid PSU Ranking");
2243 return false;
2244 }
2245 std::set<uint8_t> confSet;
2246 for (uint8_t i = 0; i < num; i++)
2247 {
2248 if (conf[i] > num)
2249 {
2250 phosphor::logging::log<phosphor::logging::level::ERR>(
2251 "PSU Ranking is larger than current PSU number");
2252 return false;
2253 }
2254 confSet.emplace(conf[i]);
2255 }
2256
2257 if (confSet.size() != num)
2258 {
2259 phosphor::logging::log<phosphor::logging::level::ERR>(
2260 "duplicate PSU Ranking");
2261 return false;
2262 }
2263 return true;
2264}
2265
2266enum class crParameter
2267{
2268 crStatus = 0,
2269 crFeature = 1,
2270 rotationFeature = 2,
2271 rotationAlgo = 3,
2272 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002273 numOfPSU = 5,
2274 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002275};
2276
2277constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2278static const constexpr uint32_t oneDay = 0x15180;
2279static const constexpr uint32_t oneMonth = 0xf53700;
2280static const constexpr uint8_t userSpecific = 0x01;
2281static const constexpr uint8_t crSetCompleted = 0;
2282ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2283 uint8_t parameter,
2284 ipmi::message::Payload& payload)
2285{
2286 switch (static_cast<crParameter>(parameter))
2287 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002288 case crParameter::rotationFeature:
2289 {
2290 uint8_t param1;
2291 if (payload.unpack(param1) || !payload.fullyUnpacked())
2292 {
2293 return ipmi::responseReqDataLenInvalid();
2294 }
2295 // Rotation Enable can only be true or false
2296 if (param1 > 1)
2297 {
2298 return ipmi::responseInvalidFieldRequest();
2299 }
2300 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2301 {
2302 return ipmi::responseResponseError();
2303 }
2304 break;
2305 }
2306 case crParameter::rotationAlgo:
2307 {
2308 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2309 std::string algoName;
2310 uint8_t param1;
2311 if (payload.unpack(param1))
2312 {
2313 return ipmi::responseReqDataLenInvalid();
2314 }
2315 switch (param1)
2316 {
2317 case 0:
2318 algoName = "xyz.openbmc_project.Control."
2319 "PowerSupplyRedundancy.Algo.bmcSpecific";
2320 break;
2321 case 1:
2322 algoName = "xyz.openbmc_project.Control."
2323 "PowerSupplyRedundancy.Algo.userSpecific";
2324 break;
2325 default:
2326 return ipmi::responseInvalidFieldRequest();
2327 }
2328 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2329 {
2330 return ipmi::responseResponseError();
2331 }
2332
2333 uint8_t numberOfPSU = getPSUCount();
2334 if (!numberOfPSU)
2335 {
2336 return ipmi::responseResponseError();
2337 }
2338 std::vector<uint8_t> rankOrder;
2339
2340 if (param1 == userSpecific)
2341 {
2342 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2343 {
2344 ipmi::responseReqDataLenInvalid();
2345 }
Yong Li83315132019-10-23 17:42:24 +08002346 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002347 {
2348 return ipmi::responseReqDataLenInvalid();
2349 }
2350
2351 if (!validateCRAlgo(rankOrder, numberOfPSU))
2352 {
2353 return ipmi::responseInvalidFieldRequest();
2354 }
2355 }
2356 else
2357 {
2358 if (rankOrder.size() > 0)
2359 {
2360 return ipmi::responseReqDataLenInvalid();
2361 }
2362 for (uint8_t i = 1; i <= numberOfPSU; i++)
2363 {
2364 rankOrder.emplace_back(i);
2365 }
2366 }
2367 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2368 {
2369 return ipmi::responseResponseError();
2370 }
2371 break;
2372 }
2373 case crParameter::rotationPeriod:
2374 {
2375 // Minimum Rotation period is One day (86400 seconds) and Max
2376 // Rotation Period is 6 month (0xf53700 seconds)
2377 uint32_t period;
2378 if (payload.unpack(period) || !payload.fullyUnpacked())
2379 {
2380 return ipmi::responseReqDataLenInvalid();
2381 }
2382 if ((period < oneDay) || (period > oneMonth))
2383 {
2384 return ipmi::responseInvalidFieldRequest();
2385 }
2386 if (setCRConfig(ctx, "PeriodOfRotation", period))
2387 {
2388 return ipmi::responseResponseError();
2389 }
2390 break;
2391 }
2392 default:
2393 {
2394 return ipmi::response(ccParameterNotSupported);
2395 }
2396 }
2397
Cheng C Yang773703a2019-08-15 09:41:11 +08002398 return ipmi::responseSuccess(crSetCompleted);
2399}
2400
Yong Li83315132019-10-23 17:42:24 +08002401ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002402 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2403{
2404 crConfigVariant value;
2405 switch (static_cast<crParameter>(parameter))
2406 {
2407 case crParameter::crStatus:
2408 {
2409 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2410 {
2411 return ipmi::responseResponseError();
2412 }
2413 std::string* pStatus = std::get_if<std::string>(&value);
2414 if (!pStatus)
2415 {
2416 phosphor::logging::log<phosphor::logging::level::ERR>(
2417 "Error to get ColdRedundancyStatus property");
2418 return ipmi::responseResponseError();
2419 }
2420 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2421 auto status =
2422 server::PowerSupplyRedundancy::convertStatusFromString(
2423 *pStatus);
2424 switch (status)
2425 {
2426 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002427 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002428 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002429
2430 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002431 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002432 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002433 default:
2434 phosphor::logging::log<phosphor::logging::level::ERR>(
2435 "Error to get valid status");
2436 return ipmi::responseResponseError();
2437 }
2438 }
2439 case crParameter::crFeature:
2440 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002441 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002442 {
2443 return ipmi::responseResponseError();
2444 }
2445 bool* pResponse = std::get_if<bool>(&value);
2446 if (!pResponse)
2447 {
2448 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002449 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002450 return ipmi::responseResponseError();
2451 }
2452
Cheng C Yangf41e3342019-09-10 04:47:23 +08002453 return ipmi::responseSuccess(parameter,
2454 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002455 }
2456 case crParameter::rotationFeature:
2457 {
2458 if (getCRConfig(ctx, "RotationEnabled", value))
2459 {
2460 return ipmi::responseResponseError();
2461 }
2462 bool* pResponse = std::get_if<bool>(&value);
2463 if (!pResponse)
2464 {
2465 phosphor::logging::log<phosphor::logging::level::ERR>(
2466 "Error to get RotationEnabled property");
2467 return ipmi::responseResponseError();
2468 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002469 return ipmi::responseSuccess(parameter,
2470 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002471 }
2472 case crParameter::rotationAlgo:
2473 {
2474 if (getCRConfig(ctx, "RotationAlgorithm", value))
2475 {
2476 return ipmi::responseResponseError();
2477 }
2478
2479 std::string* pAlgo = std::get_if<std::string>(&value);
2480 if (!pAlgo)
2481 {
2482 phosphor::logging::log<phosphor::logging::level::ERR>(
2483 "Error to get RotationAlgorithm property");
2484 return ipmi::responseResponseError();
2485 }
Yong Li83315132019-10-23 17:42:24 +08002486 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002487 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2488 auto algo =
2489 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002490
Cheng C Yang773703a2019-08-15 09:41:11 +08002491 switch (algo)
2492 {
2493 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002494 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002495 break;
2496 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002497 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002498 break;
2499 default:
2500 phosphor::logging::log<phosphor::logging::level::ERR>(
2501 "Error to get valid algo");
2502 return ipmi::responseResponseError();
2503 }
2504
2505 if (getCRConfig(ctx, "RotationRankOrder", value))
2506 {
2507 return ipmi::responseResponseError();
2508 }
2509 std::vector<uint8_t>* pResponse =
2510 std::get_if<std::vector<uint8_t>>(&value);
2511 if (!pResponse)
2512 {
2513 phosphor::logging::log<phosphor::logging::level::ERR>(
2514 "Error to get RotationRankOrder property");
2515 return ipmi::responseResponseError();
2516 }
Yong Li83315132019-10-23 17:42:24 +08002517
Cheng C Yang773703a2019-08-15 09:41:11 +08002518 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002519 std::back_inserter(response));
2520
Cheng C Yangf41e3342019-09-10 04:47:23 +08002521 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002522 }
2523 case crParameter::rotationPeriod:
2524 {
2525 if (getCRConfig(ctx, "PeriodOfRotation", value))
2526 {
2527 return ipmi::responseResponseError();
2528 }
2529 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2530 if (!pResponse)
2531 {
2532 phosphor::logging::log<phosphor::logging::level::ERR>(
2533 "Error to get RotationAlgorithm property");
2534 return ipmi::responseResponseError();
2535 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002536 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002537 }
2538 case crParameter::numOfPSU:
2539 {
2540 uint8_t numberOfPSU = getPSUCount();
2541 if (!numberOfPSU)
2542 {
2543 return ipmi::responseResponseError();
2544 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002545 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002546 }
Yong Li19445ab2019-12-20 18:25:29 +08002547 case crParameter::rotationRankOrderEffective:
2548 {
2549 if (getCRConfig(ctx, "RotationRankOrder", value,
2550 "xyz.openbmc_project.PSURedundancy"))
2551 {
2552 return ipmi::responseResponseError();
2553 }
2554 std::vector<uint8_t>* pResponse =
2555 std::get_if<std::vector<uint8_t>>(&value);
2556 if (!pResponse)
2557 {
2558 phosphor::logging::log<phosphor::logging::level::ERR>(
2559 "Error to get effective RotationRankOrder property");
2560 return ipmi::responseResponseError();
2561 }
2562 return ipmi::responseSuccess(parameter, *pResponse);
2563 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002564 default:
2565 {
2566 return ipmi::response(ccParameterNotSupported);
2567 }
2568 }
2569}
2570
Zhu, Yungebe560b02019-04-21 21:19:21 -04002571ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2572 uint8_t faultState,
2573 uint8_t faultGroup,
2574 std::array<uint8_t, 8>& ledStateData)
2575{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002576 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2577 static const std::array<std::string, maxFaultType> faultNames = {
2578 "faultFan", "faultTemp", "faultPower",
2579 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002580
2581 constexpr uint8_t maxFaultSource = 0x4;
2582 constexpr uint8_t skipLEDs = 0xFF;
2583 constexpr uint8_t pinSize = 64;
2584 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002585 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002586
Zhikui Rence4e73f2019-12-06 13:59:47 -08002587 // same pin names need to be defined in dts file
2588 static const std::array<std::array<std::string, groupSize>, groupNum>
2589 faultLedPinNames = {{
2590 "LED_CPU1_CH1_DIMM1_FAULT",
2591 "LED_CPU1_CH1_DIMM2_FAULT",
2592 "LED_CPU1_CH2_DIMM1_FAULT",
2593 "LED_CPU1_CH2_DIMM2_FAULT",
2594 "LED_CPU1_CH3_DIMM1_FAULT",
2595 "LED_CPU1_CH3_DIMM2_FAULT",
2596 "LED_CPU1_CH4_DIMM1_FAULT",
2597 "LED_CPU1_CH4_DIMM2_FAULT",
2598 "LED_CPU1_CH5_DIMM1_FAULT",
2599 "LED_CPU1_CH5_DIMM2_FAULT",
2600 "LED_CPU1_CH6_DIMM1_FAULT",
2601 "LED_CPU1_CH6_DIMM2_FAULT",
2602 "",
2603 "",
2604 "",
2605 "", // end of group1
2606 "LED_CPU2_CH1_DIMM1_FAULT",
2607 "LED_CPU2_CH1_DIMM2_FAULT",
2608 "LED_CPU2_CH2_DIMM1_FAULT",
2609 "LED_CPU2_CH2_DIMM2_FAULT",
2610 "LED_CPU2_CH3_DIMM1_FAULT",
2611 "LED_CPU2_CH3_DIMM2_FAULT",
2612 "LED_CPU2_CH4_DIMM1_FAULT",
2613 "LED_CPU2_CH4_DIMM2_FAULT",
2614 "LED_CPU2_CH5_DIMM1_FAULT",
2615 "LED_CPU2_CH5_DIMM2_FAULT",
2616 "LED_CPU2_CH6_DIMM1_FAULT",
2617 "LED_CPU2_CH6_DIMM2_FAULT",
2618 "",
2619 "",
2620 "",
2621 "", // endof group2
2622 "LED_CPU3_CH1_DIMM1_FAULT",
2623 "LED_CPU3_CH1_DIMM2_FAULT",
2624 "LED_CPU3_CH2_DIMM1_FAULT",
2625 "LED_CPU3_CH2_DIMM2_FAULT",
2626 "LED_CPU3_CH3_DIMM1_FAULT",
2627 "LED_CPU3_CH3_DIMM2_FAULT",
2628 "LED_CPU3_CH4_DIMM1_FAULT",
2629 "LED_CPU3_CH4_DIMM2_FAULT",
2630 "LED_CPU3_CH5_DIMM1_FAULT",
2631 "LED_CPU3_CH5_DIMM2_FAULT",
2632 "LED_CPU3_CH6_DIMM1_FAULT",
2633 "LED_CPU3_CH6_DIMM2_FAULT",
2634 "",
2635 "",
2636 "",
2637 "", // end of group3
2638 "LED_CPU4_CH1_DIMM1_FAULT",
2639 "LED_CPU4_CH1_DIMM2_FAULT",
2640 "LED_CPU4_CH2_DIMM1_FAULT",
2641 "LED_CPU4_CH2_DIMM2_FAULT",
2642 "LED_CPU4_CH3_DIMM1_FAULT",
2643 "LED_CPU4_CH3_DIMM2_FAULT",
2644 "LED_CPU4_CH4_DIMM1_FAULT",
2645 "LED_CPU4_CH4_DIMM2_FAULT",
2646 "LED_CPU4_CH5_DIMM1_FAULT",
2647 "LED_CPU4_CH5_DIMM2_FAULT",
2648 "LED_CPU4_CH6_DIMM1_FAULT",
2649 "LED_CPU4_CH6_DIMM2_FAULT",
2650 "",
2651 "",
2652 "",
2653 "", // end of group4
2654 "LED_FAN1_FAULT",
2655 "LED_FAN2_FAULT",
2656 "LED_FAN3_FAULT",
2657 "LED_FAN4_FAULT",
2658 "LED_FAN5_FAULT",
2659 "LED_FAN6_FAULT",
2660 "LED_FAN7_FAULT",
2661 "LED_FAN8_FAULT",
2662 "",
2663 "",
2664 "",
2665 "",
2666 "",
2667 "",
2668 "",
2669 "" // end of group5
2670 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002671
Zhikui Rence4e73f2019-12-06 13:59:47 -08002672 // Validate the source, fault type --
2673 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2674 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2675 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2676 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2677 // definition differs based on fault type (Byte 2)
2678 // Type Fan=> Group: 0=FanGroupID, FF-not used
2679 // Byte 5-11 00h, not used
2680 // Byte12 FanLedState [7:0]-Fans 7:0
2681 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2682 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2683 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2684 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2685 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2686 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2687 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2688 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002689 if ((sourceId >= maxFaultSource) ||
2690 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2691 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2692 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2693 {
2694 return ipmi::responseParmOutOfRange();
2695 }
2696
Zhikui Rence4e73f2019-12-06 13:59:47 -08002697 size_t pinGroupOffset = 0;
2698 size_t pinGroupMax = pinSize / groupSize;
2699 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002700 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002701 pinGroupOffset = 4;
2702 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002703 }
2704
2705 switch (RemoteFaultType(faultType))
2706 {
2707 case (RemoteFaultType::fan):
2708 case (RemoteFaultType::memory):
2709 {
2710 if (faultGroup == skipLEDs)
2711 {
2712 return ipmi::responseSuccess();
2713 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002714 // calculate led state bit filed count, each byte has 8bits
2715 // the maximum bits will be 8 * 8 bits
2716 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002717
2718 // assemble ledState
2719 uint64_t ledState = 0;
2720 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002721 for (int i = 0; i < sizeof(ledStateData); i++)
2722 {
2723 ledState = (uint64_t)(ledState << 8);
2724 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2725 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002726 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002727
Zhikui Rence4e73f2019-12-06 13:59:47 -08002728 for (int group = 0; group < pinGroupMax; group++)
2729 {
2730 for (int i = 0; i < groupSize; i++)
2731 { // skip non-existing pins
2732 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2733 {
2734 continue;
2735 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002736
Zhikui Rence4e73f2019-12-06 13:59:47 -08002737 gpiod::line line = gpiod::find_line(
2738 faultLedPinNames[group + pinGroupOffset][i]);
2739 if (!line)
2740 {
2741 phosphor::logging::log<phosphor::logging::level::ERR>(
2742 "Not Find Led Gpio Device!",
2743 phosphor::logging::entry(
2744 "DEVICE=%s",
2745 faultLedPinNames[group + pinGroupOffset][i]
2746 .c_str()));
2747 hasError = true;
2748 continue;
2749 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002750
Zhikui Rence4e73f2019-12-06 13:59:47 -08002751 bool activeHigh =
2752 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2753 try
2754 {
2755 line.request(
2756 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2757 activeHigh
2758 ? 0
2759 : gpiod::line_request::FLAG_ACTIVE_LOW});
2760 line.set_value(ledStateBits[i + group * groupSize]);
2761 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002762 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002763 {
2764 phosphor::logging::log<phosphor::logging::level::ERR>(
2765 "Error write Led Gpio Device!",
2766 phosphor::logging::entry(
2767 "DEVICE=%s",
2768 faultLedPinNames[group + pinGroupOffset][i]
2769 .c_str()));
2770 hasError = true;
2771 continue;
2772 }
2773 } // for int i
2774 }
2775 if (hasError)
2776 {
2777 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002778 }
2779 break;
2780 }
2781 default:
2782 {
2783 // now only support two fault types
2784 return ipmi::responseParmOutOfRange();
2785 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002786 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002787 return ipmi::responseSuccess();
2788}
2789
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302790ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2791{
2792 uint8_t prodId = 0;
2793 try
2794 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002795 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302796 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002797 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302798 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2799 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002800 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302801 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2802 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302803 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2804 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002805 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302806 {
2807 phosphor::logging::log<phosphor::logging::level::ERR>(
2808 "ipmiOEMReadBoardProductId: Product ID read failed!",
2809 phosphor::logging::entry("ERR=%s", e.what()));
2810 }
2811 return ipmi::responseSuccess(prodId);
2812}
2813
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302814/** @brief implements the get security mode command
2815 * @param ctx - ctx pointer
2816 *
2817 * @returns IPMI completion code with following data
2818 * - restriction mode value - As specified in
2819 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2820 * - special mode value - As specified in
2821 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2822 */
2823ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2824{
2825 namespace securityNameSpace =
2826 sdbusplus::xyz::openbmc_project::Control::Security::server;
2827 uint8_t restrictionModeValue = 0;
2828 uint8_t specialModeValue = 0;
2829
2830 boost::system::error_code ec;
2831 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002832 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302833 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2834 restricionModeProperty);
2835 if (ec)
2836 {
2837 phosphor::logging::log<phosphor::logging::level::ERR>(
2838 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2839 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2840 return ipmi::responseUnspecifiedError();
2841 }
2842 restrictionModeValue = static_cast<uint8_t>(
2843 securityNameSpace::RestrictionMode::convertModesFromString(
2844 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302845 auto varSpecialMode =
2846 ctx->bus->yield_method_call<std::variant<std::string>>(
2847 ctx->yield, ec, specialModeService, specialModeBasePath,
2848 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2849 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302850 if (ec)
2851 {
2852 phosphor::logging::log<phosphor::logging::level::ERR>(
2853 "ipmiGetSecurityMode: failed to get SpecialMode property",
2854 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2855 // fall through, let us not worry about SpecialMode property, which is
2856 // not required in user scenario
2857 }
2858 else
2859 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302860 specialModeValue = static_cast<uint8_t>(
2861 securityNameSpace::SpecialMode::convertModesFromString(
2862 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302863 }
2864 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2865}
2866
2867/** @brief implements the set security mode command
2868 * Command allows to upgrade the restriction mode and won't allow
2869 * to downgrade from system interface
2870 * @param ctx - ctx pointer
2871 * @param restrictionMode - restriction mode value to be set.
2872 *
2873 * @returns IPMI completion code
2874 */
2875ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302876 uint8_t restrictionMode,
2877 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302878{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302879#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2880 if (specialMode)
2881 {
2882 return ipmi::responseReqDataLenInvalid();
2883 }
2884#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302885 namespace securityNameSpace =
2886 sdbusplus::xyz::openbmc_project::Control::Security::server;
2887
2888 ChannelInfo chInfo;
2889 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2890 {
2891 phosphor::logging::log<phosphor::logging::level::ERR>(
2892 "ipmiSetSecurityMode: Failed to get Channel Info",
2893 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2894 return ipmi::responseUnspecifiedError();
2895 }
2896 auto reqMode =
2897 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2898
2899 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2900 (reqMode >
2901 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2902 {
2903 return ipmi::responseInvalidFieldRequest();
2904 }
2905
2906 boost::system::error_code ec;
2907 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002908 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302909 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2910 restricionModeProperty);
2911 if (ec)
2912 {
2913 phosphor::logging::log<phosphor::logging::level::ERR>(
2914 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2915 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2916 return ipmi::responseUnspecifiedError();
2917 }
2918 auto currentRestrictionMode =
2919 securityNameSpace::RestrictionMode::convertModesFromString(
2920 std::get<std::string>(varRestrMode));
2921
2922 if (chInfo.mediumType !=
2923 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2924 currentRestrictionMode > reqMode)
2925 {
2926 phosphor::logging::log<phosphor::logging::level::ERR>(
2927 "ipmiSetSecurityMode - Downgrading security mode not supported "
2928 "through system interface",
2929 phosphor::logging::entry(
2930 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2931 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2932 return ipmi::responseCommandNotAvailable();
2933 }
2934
2935 ec.clear();
2936 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002937 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302938 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2939 restricionModeProperty,
2940 static_cast<std::variant<std::string>>(
2941 securityNameSpace::convertForMessage(reqMode)));
2942
2943 if (ec)
2944 {
2945 phosphor::logging::log<phosphor::logging::level::ERR>(
2946 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2947 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2948 return ipmi::responseUnspecifiedError();
2949 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302950
2951#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2952 if (specialMode)
2953 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00002954 constexpr uint8_t mfgMode = 0x01;
2955 // Manufacturing mode is reserved. So can't enable this mode.
2956 if (specialMode.value() == mfgMode)
2957 {
2958 phosphor::logging::log<phosphor::logging::level::INFO>(
2959 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
2960 return ipmi::responseInvalidFieldRequest();
2961 }
2962
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302963 ec.clear();
2964 ctx->bus->yield_method_call<>(
2965 ctx->yield, ec, specialModeService, specialModeBasePath,
2966 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2967 specialModeProperty,
2968 static_cast<std::variant<std::string>>(
2969 securityNameSpace::convertForMessage(
2970 static_cast<securityNameSpace::SpecialMode::Modes>(
2971 specialMode.value()))));
2972
2973 if (ec)
2974 {
2975 phosphor::logging::log<phosphor::logging::level::ERR>(
2976 "ipmiSetSecurityMode: failed to set SpecialMode property",
2977 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2978 return ipmi::responseUnspecifiedError();
2979 }
2980 }
2981#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302982 return ipmi::responseSuccess();
2983}
2984
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002985ipmi::RspType<uint8_t /* restore status */>
2986 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2987{
2988 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2989
2990 if (clr != expClr)
2991 {
2992 return ipmi::responseInvalidFieldRequest();
2993 }
2994 constexpr uint8_t cmdStatus = 0;
2995 constexpr uint8_t cmdDefaultRestore = 0xaa;
2996 constexpr uint8_t cmdFullRestore = 0xbb;
2997 constexpr uint8_t cmdFormat = 0xcc;
2998
2999 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3000
3001 switch (cmd)
3002 {
3003 case cmdStatus:
3004 break;
3005 case cmdDefaultRestore:
3006 case cmdFullRestore:
3007 case cmdFormat:
3008 {
3009 // write file to rwfs root
3010 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3011 std::ofstream restoreFile(restoreOpFname);
3012 if (!restoreFile)
3013 {
3014 return ipmi::responseUnspecifiedError();
3015 }
3016 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303017
3018 phosphor::logging::log<phosphor::logging::level::WARNING>(
3019 "Restore to default will be performed on next BMC boot",
3020 phosphor::logging::entry("ACTION=0x%0X", cmd));
3021
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003022 break;
3023 }
3024 default:
3025 return ipmi::responseInvalidFieldRequest();
3026 }
3027
3028 constexpr uint8_t restorePending = 0;
3029 constexpr uint8_t restoreComplete = 1;
3030
3031 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3032 ? restorePending
3033 : restoreComplete;
3034 return ipmi::responseSuccess(restoreStatus);
3035}
3036
Chen Yugang39736d52019-07-12 16:24:33 +08003037ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3038{
3039 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003040 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003041
3042 try
3043 {
3044 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3045 std::string service =
3046 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
3047 Value variant =
3048 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3049 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
3050
3051 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3052 std::get<std::string>(variant)))
3053 {
3054 case nmi::NMISource::BMCSourceSignal::None:
3055 bmcSource = static_cast<uint8_t>(NmiSource::none);
3056 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003057 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3058 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003059 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003060 case nmi::NMISource::BMCSourceSignal::Watchdog:
3061 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003062 break;
3063 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3064 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3065 break;
3066 case nmi::NMISource::BMCSourceSignal::MemoryError:
3067 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3068 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003069 case nmi::NMISource::BMCSourceSignal::PciBusError:
3070 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003071 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003072 case nmi::NMISource::BMCSourceSignal::PCH:
3073 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003074 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003075 case nmi::NMISource::BMCSourceSignal::Chipset:
3076 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003077 break;
3078 default:
3079 phosphor::logging::log<phosphor::logging::level::ERR>(
3080 "NMI source: invalid property!",
3081 phosphor::logging::entry(
3082 "PROP=%s", std::get<std::string>(variant).c_str()));
3083 return ipmi::responseResponseError();
3084 }
3085 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003086 catch (const sdbusplus::exception::exception& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003087 {
3088 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3089 return ipmi::responseResponseError();
3090 }
3091
3092 return ipmi::responseSuccess(bmcSource);
3093}
3094
3095ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3096{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003097 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003098
3099 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3100 nmi::NMISource::BMCSourceSignal::None;
3101
3102 switch (NmiSource(sourceId))
3103 {
3104 case NmiSource::none:
3105 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3106 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003107 case NmiSource::frontPanelButton:
3108 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003109 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003110 case NmiSource::watchdog:
3111 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003112 break;
3113 case NmiSource::chassisCmd:
3114 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3115 break;
3116 case NmiSource::memoryError:
3117 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3118 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003119 case NmiSource::pciBusError:
3120 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003121 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003122 case NmiSource::pch:
3123 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003124 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003125 case NmiSource::chipset:
3126 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003127 break;
3128 default:
3129 phosphor::logging::log<phosphor::logging::level::ERR>(
3130 "NMI source: invalid property!");
3131 return ipmi::responseResponseError();
3132 }
3133
3134 try
3135 {
3136 // keep NMI signal source
3137 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3138 std::string service =
3139 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003140 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3141 oemNmiBmcSourceObjPathProp,
3142 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003143 // set Enabled property to inform NMI source handling
3144 // to trigger a NMI_OUT BSOD.
3145 // if it's triggered by NMI source property changed,
3146 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3147 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3148 {
3149 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3150 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3151 static_cast<bool>(true));
3152 }
Chen Yugang39736d52019-07-12 16:24:33 +08003153 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003154 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003155 {
3156 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3157 return ipmi::responseResponseError();
3158 }
3159
3160 return ipmi::responseSuccess();
3161}
3162
James Feist63efafa2019-07-24 12:39:21 -07003163namespace dimmOffset
3164{
3165constexpr const char* dimmPower = "DimmPower";
3166constexpr const char* staticCltt = "StaticCltt";
3167constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3168constexpr const char* offsetInterface =
3169 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3170constexpr const char* property = "DimmOffset";
3171
3172}; // namespace dimmOffset
3173
3174ipmi::RspType<>
3175 ipmiOEMSetDimmOffset(uint8_t type,
3176 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3177{
3178 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3179 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3180 {
3181 return ipmi::responseInvalidFieldRequest();
3182 }
3183
3184 if (data.empty())
3185 {
3186 return ipmi::responseInvalidFieldRequest();
3187 }
3188 nlohmann::json json;
3189
3190 std::ifstream jsonStream(dimmOffsetFile);
3191 if (jsonStream.good())
3192 {
3193 json = nlohmann::json::parse(jsonStream, nullptr, false);
3194 if (json.is_discarded())
3195 {
3196 json = nlohmann::json();
3197 }
3198 jsonStream.close();
3199 }
3200
3201 std::string typeName;
3202 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3203 {
3204 typeName = dimmOffset::dimmPower;
3205 }
3206 else
3207 {
3208 typeName = dimmOffset::staticCltt;
3209 }
3210
3211 nlohmann::json& field = json[typeName];
3212
3213 for (const auto& [index, value] : data)
3214 {
3215 field[index] = value;
3216 }
3217
3218 for (nlohmann::json& val : field)
3219 {
3220 if (val == nullptr)
3221 {
3222 val = static_cast<uint8_t>(0);
3223 }
3224 }
3225
3226 std::ofstream output(dimmOffsetFile);
3227 if (!output.good())
3228 {
3229 std::cerr << "Error writing json file\n";
3230 return ipmi::responseResponseError();
3231 }
3232
3233 output << json.dump(4);
3234
3235 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3236 {
3237 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3238
3239 std::variant<std::vector<uint8_t>> offsets =
3240 field.get<std::vector<uint8_t>>();
3241 auto call = bus->new_method_call(
3242 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3243 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3244 try
3245 {
3246 bus->call(call);
3247 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003248 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003249 {
3250 phosphor::logging::log<phosphor::logging::level::ERR>(
3251 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3252 phosphor::logging::entry("ERR=%s", e.what()));
3253 return ipmi::responseResponseError();
3254 }
3255 }
3256
3257 return ipmi::responseSuccess();
3258}
3259
3260ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3261{
3262
3263 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3264 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3265 {
3266 return ipmi::responseInvalidFieldRequest();
3267 }
3268
3269 std::ifstream jsonStream(dimmOffsetFile);
3270
3271 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3272 if (json.is_discarded())
3273 {
3274 std::cerr << "File error in " << dimmOffsetFile << "\n";
3275 return ipmi::responseResponseError();
3276 }
3277
3278 std::string typeName;
3279 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3280 {
3281 typeName = dimmOffset::dimmPower;
3282 }
3283 else
3284 {
3285 typeName = dimmOffset::staticCltt;
3286 }
3287
3288 auto it = json.find(typeName);
3289 if (it == json.end())
3290 {
3291 return ipmi::responseInvalidFieldRequest();
3292 }
3293
3294 if (it->size() <= index)
3295 {
3296 return ipmi::responseInvalidFieldRequest();
3297 }
3298
3299 uint8_t resp = it->at(index).get<uint8_t>();
3300 return ipmi::responseSuccess(resp);
3301}
3302
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003303namespace boot_options
3304{
3305
3306using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3307using IpmiValue = uint8_t;
3308constexpr auto ipmiDefault = 0;
3309
3310std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3311 {0x01, Source::Sources::Network},
3312 {0x02, Source::Sources::Disk},
3313 {0x05, Source::Sources::ExternalMedia},
3314 {0x0f, Source::Sources::RemovableMedia},
3315 {ipmiDefault, Source::Sources::Default}};
3316
3317std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003318 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003319
3320std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3321 {Source::Sources::Network, 0x01},
3322 {Source::Sources::Disk, 0x02},
3323 {Source::Sources::ExternalMedia, 0x05},
3324 {Source::Sources::RemovableMedia, 0x0f},
3325 {Source::Sources::Default, ipmiDefault}};
3326
3327std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003328 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003329
3330static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3331static constexpr auto bootSourceIntf =
3332 "xyz.openbmc_project.Control.Boot.Source";
3333static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3334static constexpr auto persistentObjPath =
3335 "/xyz/openbmc_project/control/host0/boot";
3336static constexpr auto oneTimePath =
3337 "/xyz/openbmc_project/control/host0/boot/one_time";
3338static constexpr auto bootSourceProp = "BootSource";
3339static constexpr auto bootModeProp = "BootMode";
3340static constexpr auto oneTimeBootEnableProp = "Enabled";
3341static constexpr auto httpBootMode =
3342 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3343
3344enum class BootOptionParameter : size_t
3345{
3346 setInProgress = 0x0,
3347 bootFlags = 0x5,
3348};
3349static constexpr uint8_t setComplete = 0x0;
3350static constexpr uint8_t setInProgress = 0x1;
3351static uint8_t transferStatus = setComplete;
3352static constexpr uint8_t setParmVersion = 0x01;
3353static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3354static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3355static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3356static constexpr uint8_t httpBoot = 0xd;
3357static constexpr uint8_t bootSourceMask = 0x3c;
3358
3359} // namespace boot_options
3360
3361ipmi::RspType<uint8_t, // version
3362 uint8_t, // param
3363 uint8_t, // data0, dependent on parameter
3364 std::optional<uint8_t> // data1, dependent on parameter
3365 >
3366 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3367{
3368 using namespace boot_options;
3369 uint8_t bootOption = 0;
3370
3371 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3372 {
3373 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3374 std::nullopt);
3375 }
3376
3377 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3378 {
3379 phosphor::logging::log<phosphor::logging::level::ERR>(
3380 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003381 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003382 }
3383
3384 try
3385 {
3386 auto oneTimeEnabled = false;
3387 // read one time Enabled property
3388 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3389 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3390 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3391 enabledIntf, oneTimeBootEnableProp);
3392 oneTimeEnabled = std::get<bool>(variant);
3393
3394 // get BootSource and BootMode properties
3395 // according to oneTimeEnable
3396 auto bootObjPath = oneTimePath;
3397 if (oneTimeEnabled == false)
3398 {
3399 bootObjPath = persistentObjPath;
3400 }
3401
3402 service = getService(*dbus, bootModeIntf, bootObjPath);
3403 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3404 bootModeProp);
3405
3406 auto bootMode =
3407 Mode::convertModesFromString(std::get<std::string>(variant));
3408
3409 service = getService(*dbus, bootSourceIntf, bootObjPath);
3410 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3411 bootSourceProp);
3412
3413 if (std::get<std::string>(variant) == httpBootMode)
3414 {
3415 bootOption = httpBoot;
3416 }
3417 else
3418 {
3419 auto bootSource = Source::convertSourcesFromString(
3420 std::get<std::string>(variant));
3421 bootOption = sourceDbusToIpmi.at(bootSource);
3422 if (Source::Sources::Default == bootSource)
3423 {
3424 bootOption = modeDbusToIpmi.at(bootMode);
3425 }
3426 }
3427
3428 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3429 : setParmBootFlagsValidPermanent;
3430 bootOption <<= 2; // shift for responseconstexpr
3431 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3432 bootOption);
3433 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003434 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003435 {
3436 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3437 return ipmi::responseResponseError();
3438 }
3439}
3440
3441ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3442 std::optional<uint8_t> bootOption)
3443{
3444 using namespace boot_options;
3445 auto oneTimeEnabled = false;
3446
3447 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3448 {
3449 if (bootOption)
3450 {
3451 return ipmi::responseReqDataLenInvalid();
3452 }
3453
3454 if (transferStatus == setInProgress)
3455 {
3456 phosphor::logging::log<phosphor::logging::level::ERR>(
3457 "boot option set in progress!");
3458 return ipmi::responseResponseError();
3459 }
3460
3461 transferStatus = bootParam;
3462 return ipmi::responseSuccess();
3463 }
3464
3465 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3466 {
3467 phosphor::logging::log<phosphor::logging::level::ERR>(
3468 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003469 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003470 }
3471
3472 if (!bootOption)
3473 {
3474 return ipmi::responseReqDataLenInvalid();
3475 }
3476
3477 if (((bootOption.value() & bootSourceMask) >> 2) !=
3478 httpBoot) // not http boot, exit
3479 {
3480 phosphor::logging::log<phosphor::logging::level::ERR>(
3481 "wrong boot option parameter!");
3482 return ipmi::responseParmOutOfRange();
3483 }
3484
3485 try
3486 {
3487 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3488 setParmBootFlagsPermanent;
3489
3490 // read one time Enabled property
3491 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3492 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3493 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3494 enabledIntf, oneTimeBootEnableProp);
3495 oneTimeEnabled = std::get<bool>(variant);
3496
3497 /*
3498 * Check if the current boot setting is onetime or permanent, if the
3499 * request in the command is otherwise, then set the "Enabled"
3500 * property in one_time object path to 'True' to indicate onetime
3501 * and 'False' to indicate permanent.
3502 *
3503 * Once the onetime/permanent setting is applied, then the bootMode
3504 * and bootSource is updated for the corresponding object.
3505 */
3506 if (permanent == oneTimeEnabled)
3507 {
3508 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3509 oneTimeBootEnableProp, !permanent);
3510 }
3511
3512 // set BootSource and BootMode properties
3513 // according to oneTimeEnable or persistent
3514 auto bootObjPath = oneTimePath;
3515 if (oneTimeEnabled == false)
3516 {
3517 bootObjPath = persistentObjPath;
3518 }
3519 std::string bootMode =
3520 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3521 std::string bootSource = httpBootMode;
3522
3523 service = getService(*dbus, bootModeIntf, bootObjPath);
3524 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3525 bootMode);
3526
3527 service = getService(*dbus, bootSourceIntf, bootObjPath);
3528 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3529 bootSourceProp, bootSource);
3530 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003531 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003532 {
3533 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3534 return ipmi::responseResponseError();
3535 }
3536
3537 return ipmi::responseSuccess();
3538}
3539
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003540using BasicVariantType =
3541 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3542 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3543 uint16_t, uint8_t, bool>;
3544using PropertyMapType =
3545 boost::container::flat_map<std::string, BasicVariantType>;
3546static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3547 "xyz.openbmc_project.Configuration.PSUPresence"};
3548int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3549 std::vector<uint64_t>& addrTable)
3550{
3551 boost::system::error_code ec;
3552 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3553 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3554 "/xyz/openbmc_project/object_mapper",
3555 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3556 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3557 if (ec)
3558 {
3559 phosphor::logging::log<phosphor::logging::level::ERR>(
3560 "Failed to set dbus property to cold redundancy");
3561 return -1;
3562 }
3563 for (const auto& object : subtree)
3564 {
3565 std::string pathName = object.first;
3566 for (const auto& serviceIface : object.second)
3567 {
3568 std::string serviceName = serviceIface.first;
3569
3570 ec.clear();
3571 PropertyMapType propMap =
3572 ctx->bus->yield_method_call<PropertyMapType>(
3573 ctx->yield, ec, serviceName, pathName,
3574 "org.freedesktop.DBus.Properties", "GetAll",
3575 "xyz.openbmc_project.Configuration.PSUPresence");
3576 if (ec)
3577 {
3578 phosphor::logging::log<phosphor::logging::level::ERR>(
3579 "Failed to set dbus property to cold redundancy");
3580 return -1;
3581 }
3582 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3583 auto psuAddress =
3584 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3585
3586 if (psuBus == nullptr || psuAddress == nullptr)
3587 {
3588 std::cerr << "error finding necessary "
3589 "entry in configuration\n";
3590 return -1;
3591 }
3592 bus = static_cast<uint8_t>(*psuBus);
3593 addrTable = *psuAddress;
3594 return 0;
3595 }
3596 }
3597 return -1;
3598}
3599
3600static const constexpr uint8_t addrOffset = 8;
3601static const constexpr uint8_t psuRevision = 0xd9;
3602static const constexpr uint8_t defaultPSUBus = 7;
3603// Second Minor, Primary Minor, Major
3604static const constexpr size_t verLen = 3;
3605ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3606{
3607 uint8_t bus = defaultPSUBus;
3608 std::vector<uint64_t> addrTable;
3609 std::vector<uint8_t> result;
3610 if (getPSUAddress(ctx, bus, addrTable))
3611 {
3612 std::cerr << "Failed to get PSU bus and address\n";
3613 return ipmi::responseResponseError();
3614 }
3615
3616 for (const auto& slaveAddr : addrTable)
3617 {
3618 std::vector<uint8_t> writeData = {psuRevision};
3619 std::vector<uint8_t> readBuf(verLen);
3620 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3621 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3622
3623 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3624 if (retI2C != ipmi::ccSuccess)
3625 {
3626 for (size_t idx = 0; idx < verLen; idx++)
3627 {
3628 result.emplace_back(0x00);
3629 }
3630 }
3631 else
3632 {
3633 for (const uint8_t& data : readBuf)
3634 {
3635 result.emplace_back(data);
3636 }
3637 }
3638 }
3639
3640 return ipmi::responseSuccess(result);
3641}
3642
srikanta mondal2030d7c2020-05-03 17:25:25 +00003643std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3644 const std::string& name)
3645{
3646 Value dbusValue = 0;
3647 std::string serviceName;
3648
3649 boost::system::error_code ec =
3650 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3651
3652 if (ec)
3653 {
3654 phosphor::logging::log<phosphor::logging::level::ERR>(
3655 "Failed to perform Multinode getService.");
3656 return std::nullopt;
3657 }
3658
3659 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3660 multiNodeIntf, name, dbusValue);
3661 if (ec)
3662 {
3663 phosphor::logging::log<phosphor::logging::level::ERR>(
3664 "Failed to perform Multinode get property");
3665 return std::nullopt;
3666 }
3667
3668 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3669 if (!multiNodeVal)
3670 {
3671 phosphor::logging::log<phosphor::logging::level::ERR>(
3672 "getMultiNodeInfoPresence: error to get multinode");
3673 return std::nullopt;
3674 }
3675 return *multiNodeVal;
3676}
3677
3678/** @brief implements OEM get reading command
3679 * @param domain ID
3680 * @param reading Type
3681 * - 00h = platform Power Consumption
3682 * - 01h = inlet Air Temp
3683 * - 02h = icc_TDC from PECI
3684 * @param reserved, write as 0000h
3685 *
3686 * @returns IPMI completion code plus response data
3687 * - response
3688 * - domain ID
3689 * - reading Type
3690 * - 00h = platform Power Consumption
3691 * - 01h = inlet Air Temp
3692 * - 02h = icc_TDC from PECI
3693 * - reading
3694 */
3695ipmi::RspType<uint4_t, // domain ID
3696 uint4_t, // reading Type
3697 uint16_t // reading Value
3698 >
3699 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3700 uint4_t readingType, uint16_t reserved)
3701{
3702 constexpr uint8_t platformPower = 0;
3703 constexpr uint8_t inletAirTemp = 1;
3704 constexpr uint8_t iccTdc = 2;
3705
3706 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3707 {
3708 return ipmi::responseInvalidFieldRequest();
3709 }
3710
3711 // This command should run only from multi-node product.
3712 // For all other platforms this command will return invalid.
3713
3714 std::optional<uint8_t> nodeInfo =
3715 getMultiNodeInfoPresence(ctx, "NodePresence");
3716 if (!nodeInfo || !*nodeInfo)
3717 {
3718 return ipmi::responseInvalidCommand();
3719 }
3720
3721 uint16_t oemReadingValue = 0;
3722 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3723 {
3724 double value = 0;
3725 boost::system::error_code ec = ipmi::getDbusProperty(
3726 ctx, "xyz.openbmc_project.HwmonTempSensor",
3727 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3728 "xyz.openbmc_project.Sensor.Value", "Value", value);
3729 if (ec)
3730 {
3731 phosphor::logging::log<phosphor::logging::level::ERR>(
3732 "Failed to get BMC Get OEM temperature",
3733 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3734 return ipmi::responseUnspecifiedError();
3735 }
3736 // Take the Inlet temperature
3737 oemReadingValue = static_cast<uint16_t>(value);
3738 }
3739 else
3740 {
3741 phosphor::logging::log<phosphor::logging::level::ERR>(
3742 "Currently Get OEM Reading support only for Inlet Air Temp");
3743 return ipmi::responseParmOutOfRange();
3744 }
3745 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3746}
3747
AppaRao Puli28972062019-11-11 02:04:45 +05303748/** @brief implements the maximum size of
3749 * bridgeable messages used between KCS and
3750 * IPMB interfacesget security mode command.
3751 *
3752 * @returns IPMI completion code with following data
3753 * - KCS Buffer Size (In multiples of four bytes)
3754 * - IPMB Buffer Size (In multiples of four bytes)
3755 **/
3756ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3757{
3758 // for now this is hard coded; really this number is dependent on
3759 // the BMC kcs driver as well as the host kcs driver....
3760 // we can't know the latter.
3761 uint8_t kcsMaxBufferSize = 63 / 4;
3762 uint8_t ipmbMaxBufferSize = 128 / 4;
3763
3764 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3765}
3766
Jason M. Bills64796042018-10-03 16:51:55 -07003767static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003768{
3769 phosphor::logging::log<phosphor::logging::level::INFO>(
3770 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003771 ipmiPrintAndRegister(intel::netFnGeneral,
3772 intel::general::cmdGetChassisIdentifier, NULL,
3773 ipmiOEMGetChassisIdentifier,
3774 PRIVILEGE_USER); // get chassis identifier
3775
3776 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3777 NULL, ipmiOEMSetSystemGUID,
3778 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003779
3780 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003781 registerHandler(prioOemBase, intel::netFnGeneral,
3782 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3783 ipmiOEMDisableBMCSystemReset);
3784
Jason M. Billsb02bf092019-08-15 13:01:56 -07003785 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003786 registerHandler(prioOemBase, intel::netFnGeneral,
3787 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3788 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003789
Vernon Mauery98bbf692019-09-16 11:14:59 -07003790 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3791 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003792
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003793 registerHandler(prioOemBase, intel::netFnGeneral,
3794 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3795 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003796
Vernon Mauery98bbf692019-09-16 11:14:59 -07003797 ipmiPrintAndRegister(intel::netFnGeneral,
3798 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3799 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303800
Vernon Mauery98bbf692019-09-16 11:14:59 -07003801 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3802 intel::general::cmdSendEmbeddedFWUpdStatus,
3803 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303804
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303805 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3806 Privilege::Admin, ipmiOEMSlotIpmb);
3807
Vernon Mauery98bbf692019-09-16 11:14:59 -07003808 ipmiPrintAndRegister(intel::netFnGeneral,
3809 intel::general::cmdSetPowerRestoreDelay, NULL,
3810 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3811
3812 ipmiPrintAndRegister(intel::netFnGeneral,
3813 intel::general::cmdGetPowerRestoreDelay, NULL,
3814 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3815
3816 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3817 intel::general::cmdSetOEMUser2Activation,
3818 Privilege::Callback, ipmiOEMSetUser2Activation);
3819
3820 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3821 intel::general::cmdSetSpecialUserPassword,
3822 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303823
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003824 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003825 registerHandler(prioOemBase, intel::netFnGeneral,
3826 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3827 ipmiOEMGetProcessorErrConfig);
3828
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003829 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003830 registerHandler(prioOemBase, intel::netFnGeneral,
3831 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3832 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003833
Vernon Mauery98bbf692019-09-16 11:14:59 -07003834 ipmiPrintAndRegister(intel::netFnGeneral,
3835 intel::general::cmdSetShutdownPolicy, NULL,
3836 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003837
Vernon Mauery98bbf692019-09-16 11:14:59 -07003838 ipmiPrintAndRegister(intel::netFnGeneral,
3839 intel::general::cmdGetShutdownPolicy, NULL,
3840 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003841
anil kumar appanaf945eee2019-09-25 23:29:11 +00003842 registerHandler(prioOemBase, intel::netFnGeneral,
3843 intel::general::cmdSetFanConfig, Privilege::User,
3844 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003845
Vernon Mauery98bbf692019-09-16 11:14:59 -07003846 registerHandler(prioOemBase, intel::netFnGeneral,
3847 intel::general::cmdGetFanConfig, Privilege::User,
3848 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003849
Vernon Mauery98bbf692019-09-16 11:14:59 -07003850 registerHandler(prioOemBase, intel::netFnGeneral,
3851 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3852 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003853
Vernon Mauery98bbf692019-09-16 11:14:59 -07003854 registerHandler(prioOemBase, intel::netFnGeneral,
3855 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3856 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003857
Vernon Mauery98bbf692019-09-16 11:14:59 -07003858 registerHandler(prioOemBase, intel::netFnGeneral,
3859 intel::general::cmdSetFscParameter, Privilege::User,
3860 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003861
Vernon Mauery98bbf692019-09-16 11:14:59 -07003862 registerHandler(prioOemBase, intel::netFnGeneral,
3863 intel::general::cmdGetFscParameter, Privilege::User,
3864 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303865
Vernon Mauery98bbf692019-09-16 11:14:59 -07003866 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3867 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3868 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003869
Vernon Mauery98bbf692019-09-16 11:14:59 -07003870 registerHandler(prioOemBase, intel::netFnGeneral,
3871 intel::general::cmdGetNmiStatus, Privilege::User,
3872 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003873
Vernon Mauery98bbf692019-09-16 11:14:59 -07003874 registerHandler(prioOemBase, intel::netFnGeneral,
3875 intel::general::cmdSetNmiStatus, Privilege::Operator,
3876 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003877
Vernon Mauery98bbf692019-09-16 11:14:59 -07003878 registerHandler(prioOemBase, intel::netFnGeneral,
3879 intel::general::cmdGetEfiBootOptions, Privilege::User,
3880 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003881
Vernon Mauery98bbf692019-09-16 11:14:59 -07003882 registerHandler(prioOemBase, intel::netFnGeneral,
3883 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3884 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303885
Vernon Mauery98bbf692019-09-16 11:14:59 -07003886 registerHandler(prioOemBase, intel::netFnGeneral,
3887 intel::general::cmdGetSecurityMode, Privilege::User,
3888 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303889
Vernon Mauery98bbf692019-09-16 11:14:59 -07003890 registerHandler(prioOemBase, intel::netFnGeneral,
3891 intel::general::cmdSetSecurityMode, Privilege::Admin,
3892 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003893
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003894 registerHandler(prioOemBase, intel::netFnGeneral,
3895 intel::general::cmdGetLEDStatus, Privilege::Admin,
3896 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003897
Vernon Mauery98bbf692019-09-16 11:14:59 -07003898 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3899 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3900 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3901
3902 registerHandler(prioOemBase, intel::netFnGeneral,
3903 intel::general::cmdSetFaultIndication, Privilege::Operator,
3904 ipmiOEMSetFaultIndication);
3905
3906 registerHandler(prioOemBase, intel::netFnGeneral,
3907 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3908 ipmiOEMSetCRConfig);
3909
3910 registerHandler(prioOemBase, intel::netFnGeneral,
3911 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3912 ipmiOEMGetCRConfig);
3913
3914 registerHandler(prioOemBase, intel::netFnGeneral,
3915 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003916 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003917
Vernon Mauery98bbf692019-09-16 11:14:59 -07003918 registerHandler(prioOemBase, intel::netFnGeneral,
3919 intel::general::cmdSetDimmOffset, Privilege::Operator,
3920 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003921
Vernon Mauery98bbf692019-09-16 11:14:59 -07003922 registerHandler(prioOemBase, intel::netFnGeneral,
3923 intel::general::cmdGetDimmOffset, Privilege::Operator,
3924 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003925
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003926 registerHandler(prioOemBase, intel::netFnGeneral,
3927 intel::general::cmdGetPSUVersion, Privilege::User,
3928 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303929
3930 registerHandler(prioOemBase, intel::netFnGeneral,
3931 intel::general::cmdGetBufferSize, Privilege::User,
3932 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00003933
3934 registerHandler(prioOemBase, intel::netFnGeneral,
3935 intel::general::cmdOEMGetReading, Privilege::User,
3936 ipmiOEMGetReading);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003937}
3938
3939} // namespace ipmi