blob: ea5eb12d7a7d9a3986c186eec13ee65ed52fcd21 [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>
Chau Lyc4b3d302025-08-05 06:51:14 +000026#include <boost/process/v1/child.hpp>
27#include <boost/process/v1/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>
Jason M. Bills493d7762022-05-04 11:13:19 -070047#include <fstream>
James Feistfcd2d3a2020-05-28 10:38:15 -070048#include <iostream>
49#include <regex>
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +000050#include <set>
James Feistfcd2d3a2020-05-28 10:38:15 -070051#include <string>
52#include <variant>
53#include <vector>
54
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080055namespace ipmi
56{
Jason M. Bills64796042018-10-03 16:51:55 -070057static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070058
Jason M. Bills64796042018-10-03 16:51:55 -070059static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080060
Suryakanth Sekard509eb92018-11-15 17:44:11 +053061static constexpr auto ethernetIntf =
62 "xyz.openbmc_project.Network.EthernetInterface";
63static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
64static constexpr auto networkService = "xyz.openbmc_project.Network";
65static constexpr auto networkRoot = "/xyz/openbmc_project/network";
66
Chen Yugang97cf96e2019-11-01 08:55:11 +080067static constexpr const char* oemNmiSourceIntf =
68 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080069static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080070 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080071static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
72static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
73
James Feist63efafa2019-07-24 12:39:21 -070074static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
srikanta mondal2030d7c2020-05-03 17:25:25 +000075static constexpr const char* multiNodeObjPath =
76 "/xyz/openbmc_project/MultiNode/Status";
77static constexpr const char* multiNodeIntf =
78 "xyz.openbmc_project.Chassis.MultiNode";
James Feist63efafa2019-07-24 12:39:21 -070079
Chen Yugang39736d52019-07-12 16:24:33 +080080enum class NmiSource : uint8_t
81{
82 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080083 frontPanelButton = 1,
84 watchdog = 2,
85 chassisCmd = 3,
86 memoryError = 4,
87 pciBusError = 5,
88 pch = 6,
89 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080090};
91
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053092enum class SpecialUserIndex : uint8_t
93{
94 rootUser = 0,
95 atScaleDebugUser = 1
96};
97
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053098static constexpr const char* restricionModeService =
99 "xyz.openbmc_project.RestrictionMode.Manager";
100static constexpr const char* restricionModeBasePath =
101 "/xyz/openbmc_project/control/security/restriction_mode";
102static constexpr const char* restricionModeIntf =
103 "xyz.openbmc_project.Control.Security.RestrictionMode";
104static constexpr const char* restricionModeProperty = "RestrictionMode";
105
106static constexpr const char* specialModeService =
107 "xyz.openbmc_project.SpecialMode";
108static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530109 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530110static constexpr const char* specialModeIntf =
111 "xyz.openbmc_project.Security.SpecialMode";
112static constexpr const char* specialModeProperty = "SpecialMode";
113
114static constexpr const char* dBusPropertyIntf =
115 "org.freedesktop.DBus.Properties";
116static constexpr const char* dBusPropertyGetMethod = "Get";
117static constexpr const char* dBusPropertySetMethod = "Set";
118
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800119// return code: 0 successful
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500120int8_t getChassisSerialNumber(sdbusplus::bus_t& bus, std::string& serial)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800121{
122 std::string objpath = "/xyz/openbmc_project/FruDevice";
123 std::string intf = "xyz.openbmc_project.FruDeviceManager";
124 std::string service = getService(bus, intf, objpath);
125 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
126 if (valueTree.empty())
127 {
128 phosphor::logging::log<phosphor::logging::level::ERR>(
129 "No object implements interface",
130 phosphor::logging::entry("INTF=%s", intf.c_str()));
131 return -1;
132 }
133
Jason M. Bills64796042018-10-03 16:51:55 -0700134 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800135 {
136 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
137 if (interface == item.second.end())
138 {
139 continue;
140 }
141
142 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
143 if (property == interface->second.end())
144 {
145 continue;
146 }
147
148 try
149 {
150 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700151 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700152 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800153 {
154 phosphor::logging::log<phosphor::logging::level::ERR>(
155 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800156 return -1;
157 }
Jason M. Bills64796042018-10-03 16:51:55 -0700158 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800159 return 0;
160 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500161 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162 {
Jason M. Bills64796042018-10-03 16:51:55 -0700163 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800164 return -1;
165 }
166 }
167 return -1;
168}
Jason M. Bills64796042018-10-03 16:51:55 -0700169
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000170namespace mailbox
171{
172static uint8_t bus = 4;
173static std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800174static uint8_t targetAddr = 56;
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000175static constexpr auto systemRoot = "/xyz/openbmc_project/inventory/system";
176static constexpr auto sessionIntf = "xyz.openbmc_project.Configuration.PFR";
177const std::string match = "Baseboard/PFR";
178static bool i2cConfigLoaded = false;
179// Command register for UFM provisioning/access commands; read/write allowed
180// from CPU/BMC.
181static const constexpr uint8_t provisioningCommand = 0x0b;
182// Trigger register for the command set in the previous offset.
183static const constexpr uint8_t triggerCommand = 0x0c;
184// Set 0x0c to 0x05 to execute command specified at “UFM/Provisioning Command”
185// register
186static const constexpr uint8_t flushRead = 0x05;
187// FIFO read registers
188std::set<uint8_t> readFifoReg = {0x08, 0x0C, 0x0D, 0x13};
189
190// UFM Read FIFO
191static const constexpr uint8_t readFifo = 0x0e;
192
193enum registerType : uint8_t
194{
195 singleByteRegister = 0,
196 fifoReadRegister,
197
198};
199
200void loadPfrConfig(ipmi::Context::ptr& ctx, bool& i2cConfigLoaded)
201{
202 ipmi::ObjectTree objectTree;
203
204 boost::system::error_code ec = ipmi::getAllDbusObjects(
205 ctx, systemRoot, sessionIntf, match, objectTree);
206
207 if (ec)
208 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000209 phosphor::logging::log<phosphor::logging::level::ERR>(
210 "Failed to fetch PFR object from dbus",
211 phosphor::logging::entry("INTERFACE=%s", sessionIntf),
212 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
213
214 return;
215 }
216
217 for (auto& softObject : objectTree)
218 {
219 const std::string& objPath = softObject.first;
220 const std::string& serviceName = softObject.second.begin()->first;
221 // PFR object found.. check for PFR support
222 ipmi::PropertyMap result;
223
224 ec = ipmi::getAllDbusProperties(ctx, serviceName, objPath, sessionIntf,
225 result);
226
227 if (ec)
228 {
229 phosphor::logging::log<phosphor::logging::level::ERR>(
230 "Failed to fetch pfr properties",
231 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
232 return;
233 }
234
235 const uint64_t* i2cBusNum = nullptr;
236 const uint64_t* address = nullptr;
237
238 for (const auto& [propName, propVariant] : result)
239 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000240 if (propName == "Address")
241 {
242 address = std::get_if<uint64_t>(&propVariant);
243 }
244 else if (propName == "Bus")
245 {
246 i2cBusNum = std::get_if<uint64_t>(&propVariant);
247 }
248 }
249
250 if ((address == nullptr) || (i2cBusNum == nullptr))
251 {
252 phosphor::logging::log<phosphor::logging::level::ERR>(
253 "Unable to read the pfr properties");
254 return;
255 }
256
257 bus = static_cast<int>(*i2cBusNum);
258 i2cBus = "/dev/i2c-" + std::to_string(bus);
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800259 targetAddr = static_cast<int>(*address);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000260
261 i2cConfigLoaded = true;
262 }
263}
264
265void writefifo(const uint8_t cmdReg, const uint8_t val)
266{
267 // Based on the spec, writing cmdReg to address val on this device, will
268 // trigger the write FIFO operation.
269 std::vector<uint8_t> writeData = {cmdReg, val};
Jason M. Bills48437462025-01-13 14:26:02 -0800270 std::vector<uint8_t> readBuf{};
Patrick Williams1bcced02024-08-16 15:20:24 -0400271 ipmi::Cc retI2C =
272 ipmi::i2cWriteRead(i2cBus, targetAddr, writeData, readBuf);
Vernon Mauerydcff1502022-09-28 11:12:46 -0700273 if (retI2C)
274 {
275 phosphor::logging::log<phosphor::logging::level::ERR>(
276 "i2cWriteRead returns non-zero");
277 }
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000278}
279
280} // namespace mailbox
281
Vernon Maueryaf652682023-08-04 13:37:21 -0700282ipmi::RspType<std::string> ipmiOEMGetBmcVersionString()
283{
284 static std::string version{};
285 if (version.empty())
286 {
287 std::regex expr{"^VERSION_ID=(.*)$"};
288 static constexpr auto osReleasePath{"/etc/os-release"};
289 std::ifstream ifs(osReleasePath);
290 if (!ifs.is_open())
291 {
292 version = "os-release not present";
293 }
294 std::string line{};
295 while (std::getline(ifs, line))
296 {
297 std::smatch sm;
298 if (regex_match(line, sm, expr))
299 {
300 if (sm.size() == 2)
301 {
302 std::string v = sm[1].str();
303 // remove the quotes
304 v.erase(std::remove(v.begin(), v.end(), '\"'), v.end());
305 version = v;
306 break;
307 }
308 }
309 }
310 ifs.close();
311 if (version.empty())
312 {
313 version = "VERSION_ID not present";
314 }
315 }
316 return ipmi::responseSuccess(version);
317}
318
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800319// Returns the Chassis Identifier (serial #)
Vernon Mauerydcff1502022-09-28 11:12:46 -0700320ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800321 ipmi_response_t response,
Vernon Mauerydcff1502022-09-28 11:12:46 -0700322 ipmi_data_len_t dataLen, ipmi_context_t)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800323{
324 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700325 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800326 {
Jason M. Bills64796042018-10-03 16:51:55 -0700327 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +0800328 return ipmi::ccReqDataLenInvalid;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800329 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700330 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
331 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800332 {
Jason M. Bills64796042018-10-03 16:51:55 -0700333 *dataLen = serial.size(); // length will never exceed response length
334 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800335 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700336 serial.copy(resp, *dataLen);
George Liu24539a42025-07-02 16:58:00 +0800337 return ipmi::ccSuccess;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800338 }
Jason M. Bills64796042018-10-03 16:51:55 -0700339 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +0800340 return ipmi::ccResponseError;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800341}
342
Vernon Mauerydcff1502022-09-28 11:12:46 -0700343ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t, ipmi_cmd_t,
344 ipmi_request_t request, ipmi_response_t,
345 ipmi_data_len_t dataLen, ipmi_context_t)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800346{
347 static constexpr size_t safeBufferLength = 50;
348 char buf[safeBufferLength] = {0};
349 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
350
Jason M. Bills64796042018-10-03 16:51:55 -0700351 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800352 {
Jason M. Bills64796042018-10-03 16:51:55 -0700353 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +0800354 return ipmi::ccReqDataLenInvalid;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800355 }
356
Jason M. Bills64796042018-10-03 16:51:55 -0700357 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800358
359 snprintf(
360 buf, safeBufferLength,
361 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
362 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
363 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
364 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
365 Data->node3, Data->node2, Data->node1);
366 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
367 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800368
369 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
370 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700371 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
372 std::string service = getService(*dbus, intf, objpath);
373 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
George Liu24539a42025-07-02 16:58:00 +0800374 return ipmi::ccSuccess;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800375}
376
Jason M. Bills97d1fb32025-04-23 08:57:35 -0700377ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
378 uint7_t reserved1)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700379{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000380 if (reserved1)
381 {
382 return ipmi::responseInvalidFieldRequest();
383 }
384
Jason M. Billsb02bf092019-08-15 13:01:56 -0700385 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
386
387 try
388 {
Patrick Williams1bcced02024-08-16 15:20:24 -0400389 auto service =
390 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
Jason M. Billsb02bf092019-08-15 13:01:56 -0700391 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
392 bmcResetDisablesIntf, "ResetOnSMI",
393 !disableResetOnSMI);
394 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500395 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700396 {
397 phosphor::logging::log<phosphor::logging::level::ERR>(
398 "Failed to set BMC reset disables",
399 phosphor::logging::entry("EXCEPTION=%s", e.what()));
400 return ipmi::responseUnspecifiedError();
401 }
402
403 return ipmi::responseSuccess();
404}
405
406ipmi::RspType<bool, // disableResetOnSMI
407 uint7_t // reserved
408 >
409 ipmiOEMGetBMCResetDisables()
410{
411 bool disableResetOnSMI = true;
412
413 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
414 try
415 {
Patrick Williams1bcced02024-08-16 15:20:24 -0400416 auto service =
417 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
Jason M. Billsb02bf092019-08-15 13:01:56 -0700418 Value variant =
419 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
420 bmcResetDisablesIntf, "ResetOnSMI");
421 disableResetOnSMI = !std::get<bool>(variant);
422 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500423 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700424 {
425 phosphor::logging::log<phosphor::logging::level::ERR>(
426 "Failed to get BMC reset disables",
427 phosphor::logging::entry("EXCEPTION=%s", e.what()));
428 return ipmi::responseUnspecifiedError();
429 }
430
431 return ipmi::responseSuccess(disableResetOnSMI, 0);
432}
433
Vernon Mauerydcff1502022-09-28 11:12:46 -0700434ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request,
435 ipmi_response_t response, ipmi_data_len_t dataLen,
436 ipmi_context_t)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800437{
438 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
439
Vernon Mauerydcff1502022-09-28 11:12:46 -0700440 if ((*dataLen < 2ul) || (*dataLen != (1ul + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800441 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800442 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +0800443 return ipmi::ccReqDataLenInvalid;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800444 }
Jason M. Bills64796042018-10-03 16:51:55 -0700445 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000446 for (auto idChar : idString)
447 {
448 if (!std::isprint(static_cast<unsigned char>(idChar)))
449 {
450 phosphor::logging::log<phosphor::logging::level::ERR>(
451 "BIOS ID contains non printable character");
George Liu24539a42025-07-02 16:58:00 +0800452 return ipmi::ccInvalidFieldRequest;
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000453 }
454 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800455
Vernon Mauery15419dd2019-05-24 09:40:30 -0700456 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000457 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
458 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800459 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800460 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
461 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700462 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800463 *dataLen = 1;
George Liu24539a42025-07-02 16:58:00 +0800464 return ipmi::ccSuccess;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800465}
466
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000467bool getActiveHSCSoftwareVersionInfo(std::string& hscVersion, size_t hscNumber)
468{
469 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
470 try
471 {
Patrick Williams1bcced02024-08-16 15:20:24 -0400472 std::string hsbpObjPath =
473 "/xyz/openbmc_project/software/HSBP_" + std::to_string(hscNumber);
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000474 auto service = getService(*dbus, biosVersionIntf, hsbpObjPath);
475 Value hscVersionValue =
476 getDbusProperty(*dbus, "xyz.openbmc_project.HsbpManager",
477 hsbpObjPath, biosVersionIntf, "Version");
478 hscVersion = std::get<std::string>(hscVersionValue);
479 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500480 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000481 {
482 phosphor::logging::log<phosphor::logging::level::INFO>(
483 "Failed to retrieve HSBP version information",
484 phosphor::logging::entry("HSBP Number=%d", hscNumber));
485 return false;
486 }
487 return true;
488}
489
Vernon Mauerydcff1502022-09-28 11:12:46 -0700490bool getHscVerInfo(ipmi::Context::ptr&, uint8_t& hsc0Major, uint8_t& hsc0Minor,
491 uint8_t& hsc1Major, uint8_t& hsc1Minor, uint8_t& hsc2Major,
492 uint8_t& hsc2Minor)
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000493{
494 std::string hscVersion;
495 std::array<uint8_t, 6> hscVersions{0};
496
497 for (size_t hscNumber = 1; hscNumber <= 3; hscNumber++)
498 {
499 if (!getActiveHSCSoftwareVersionInfo(hscVersion, hscNumber))
500 {
501 continue;
502 }
503 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?)");
504 constexpr size_t matchedPhosphor = 4;
505 std::smatch results;
506 // hscVersion = BOOT_VER.FPGA_VER.SECURITY_REVISION (Example: 00.02.01)
507 if (std::regex_match(hscVersion, results, pattern1))
508 {
509 // Major version is FPGA_VER and Minor version is SECURITY_REV
510 if (results.size() == matchedPhosphor)
511 {
512 int index = (hscNumber - 1) * 2;
513 hscVersions[index] =
514 static_cast<uint8_t>(std::stoi(results[2]));
515 hscVersions[index + 1] =
516 static_cast<uint8_t>(std::stoi(results[3]));
517 }
518 }
519 }
520 hsc0Major = hscVersions[0];
521 hsc0Minor = hscVersions[1];
522 hsc1Major = hscVersions[2];
523 hsc1Minor = hscVersions[3];
524 hsc2Major = hscVersions[4];
525 hsc2Minor = hscVersions[5];
526 return true;
527}
528
Vernon Mauerydcff1502022-09-28 11:12:46 -0700529bool getSwVerInfo(ipmi::Context::ptr& ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530530 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800531{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800532 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530533 std::string bmcVersion;
534 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800535 {
536 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800537 }
538
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530539 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800540 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800541 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800542 MetaRevision revision = rev.value();
543 bmcMajor = revision.major;
544
545 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
546 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
547 }
548
549 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530550 std::string meVersion;
551 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800552 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800553 return false;
554 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530555 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
556 constexpr size_t matchedPhosphor = 6;
557 std::smatch results;
558 if (std::regex_match(meVersion, results, pattern1))
559 {
560 if (results.size() == matchedPhosphor)
561 {
562 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
Patrick Williams1bcced02024-08-16 15:20:24 -0400563 meMinor = static_cast<uint8_t>(
564 std::stoi(results[2]) << 4 | std::stoi(results[3]));
AppaRao Puli32825a22020-01-17 15:52:41 +0530565 }
566 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800567 return true;
568}
569
570ipmi::RspType<
571 std::variant<std::string,
572 std::tuple<uint8_t, std::array<uint8_t, 2>,
573 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
574 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
575 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
Vernon Mauerydcff1502022-09-28 11:12:46 -0700576 ipmiOEMGetDeviceInfo(ipmi::Context::ptr& ctx, uint8_t entityType,
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530577 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530578 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800579{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800580 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
581 {
582 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800583 }
584
585 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800586 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800587 {
588 case OEMDevEntityType::biosId:
589 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530590 // Byte 2&3, Only used with selecting BIOS
591 if (!countToRead || !offset)
592 {
593 return ipmi::responseReqDataLenInvalid();
594 }
595
Vernon Mauery15419dd2019-05-24 09:40:30 -0700596 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -0400597 std::string service =
598 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800599 try
600 {
Yong Li2742b852019-12-16 14:55:11 +0800601 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000602 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800603 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700604 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530605 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800606 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800607 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800608 }
Jason M. Bills64796042018-10-03 16:51:55 -0700609 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530610 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700611 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530612 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700613 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800614 else
615 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530616 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800617 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800618
619 std::string readBuf = {0};
620 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530621 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800622 (readBuf.begin()));
623 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800624 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500625 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800626 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800627 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800628 }
629 }
630 break;
631
632 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800633 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530634 // Byte 2&3, Only used with selecting BIOS
635 if (countToRead || offset)
636 {
637 return ipmi::responseReqDataLenInvalid();
638 }
639
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800640 constexpr const size_t verLen = 2;
641 constexpr const size_t verTotalLen = 10;
642 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
643 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
644 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
645 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
646 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
647 // data0/1: BMC version number; data6/7: ME version number
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530648 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800649 {
650 return ipmi::responseUnspecifiedError();
651 }
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000652 if (!getHscVerInfo(ctx, hsc0Buf[0], hsc0Buf[1], hsc1Buf[0],
653 hsc1Buf[1], hsc2Buf[0], hsc2Buf[1]))
654 {
655 return ipmi::responseUnspecifiedError();
656 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800657 return ipmi::responseSuccess(
658 std::tuple<
659 uint8_t, std::array<uint8_t, verLen>,
660 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
661 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
662 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
663 }
664 break;
665
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800666 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800667 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530668 // Byte 2&3, Only used with selecting BIOS
669 if (countToRead || offset)
670 {
671 return ipmi::responseReqDataLenInvalid();
672 }
673
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800674 constexpr const size_t sdrLen = 2;
675 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
676 return ipmi::responseSuccess(
677 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
678 readBuf});
679 }
680 break;
681
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800682 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800683 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800684 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800685}
686
Vernon Mauerydcff1502022-09-28 11:12:46 -0700687ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
688 ipmi_response_t response, ipmi_data_len_t dataLen,
689 ipmi_context_t)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800690{
691 if (*dataLen != 0)
692 {
Jason M. Bills64796042018-10-03 16:51:55 -0700693 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +0800694 return ipmi::ccReqDataLenInvalid;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800695 }
696
697 *dataLen = 1;
698 uint8_t* res = reinterpret_cast<uint8_t*>(response);
699 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
700 // AIC is available so that BIOS will not timeout repeatly which leads to
701 // slow booting.
702 *res = 0; // Byte1=Count of SlotPosition/FruID records.
George Liu24539a42025-07-02 16:58:00 +0800703 return ipmi::ccSuccess;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800704}
705
Vernon Mauerydcff1502022-09-28 11:12:46 -0700706ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
Jason M. Bills64796042018-10-03 16:51:55 -0700707 ipmi_response_t response,
Vernon Mauerydcff1502022-09-28 11:12:46 -0700708 ipmi_data_len_t dataLen, ipmi_context_t)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800709{
Jason M. Bills64796042018-10-03 16:51:55 -0700710 GetPowerRestoreDelayRes* resp =
711 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
712
713 if (*dataLen != 0)
714 {
715 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +0800716 return ipmi::ccReqDataLenInvalid;
Jason M. Bills64796042018-10-03 16:51:55 -0700717 }
718
Vernon Mauery15419dd2019-05-24 09:40:30 -0700719 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -0400720 std::string service =
721 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
722 Value variant =
723 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
724 powerRestoreDelayIntf, powerRestoreDelayProp);
Jason M. Bills64796042018-10-03 16:51:55 -0700725
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300726 uint64_t val = std::get<uint64_t>(variant);
727 val /= 1000000UL;
728 uint16_t delay = val;
Jason M. Bills64796042018-10-03 16:51:55 -0700729 resp->byteLSB = delay;
730 resp->byteMSB = delay >> 8;
731
732 *dataLen = sizeof(GetPowerRestoreDelayRes);
733
George Liu24539a42025-07-02 16:58:00 +0800734 return ipmi::ccSuccess;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800735}
736
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800737static uint8_t bcdToDec(uint8_t val)
738{
739 return ((val / 16 * 10) + (val % 16));
740}
741
742// Allows an update utility or system BIOS to send the status of an embedded
743// firmware update attempt to the BMC. After received, BMC will create a logging
744// record.
Patrick Williams1bcced02024-08-16 15:20:24 -0400745ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(
746 uint8_t status, uint8_t target, uint8_t majorRevision,
747 uint8_t minorRevision, uint32_t auxInfo)
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800748{
749 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700750 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800751 target = (target & selEvtTargetMask) >> selEvtTargetShift;
752
753 /* make sure the status is 0, 1, or 2 as per the spec */
754 if (status > 2)
755 {
756 return ipmi::response(ipmi::ccInvalidFieldRequest);
757 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700758 /* make sure the target is 0, 1, 2, or 4 as per the spec */
759 if (target > 4 || target == 3)
760 {
761 return ipmi::response(ipmi::ccInvalidFieldRequest);
762 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800763 /*orignal OEM command is to record OEM SEL.
764 But openbmc does not support OEM SEL, so we redirect it to redfish event
765 logging. */
766 std::string buildInfo;
767 std::string action;
768 switch (FWUpdateTarget(target))
769 {
770 case FWUpdateTarget::targetBMC:
771 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700772 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800773 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
774 " BuildID: " + std::to_string(auxInfo);
775 buildInfo += std::to_string(auxInfo);
776 break;
777 case FWUpdateTarget::targetBIOS:
778 firmware = "BIOS";
779 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700780 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800781 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
782 " minor: " +
783 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
784 " ReleaseNumber: " + // ASCII encoded
785 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
786 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
787 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
788 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
789 break;
790 case FWUpdateTarget::targetME:
791 firmware = "ME";
792 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700793 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800794 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
795 " minor2: " +
796 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
797 " build1: " +
798 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
799 " build2: " +
800 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
801 break;
802 case FWUpdateTarget::targetOEMEWS:
803 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700804 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800805 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
806 " BuildID: " + std::to_string(auxInfo);
807 break;
808 }
809
Jason M. Billsdc249272019-04-03 09:58:40 -0700810 static const std::string openBMCMessageRegistryVersion("0.1");
811 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
812
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800813 switch (status)
814 {
815 case 0x0:
816 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700817 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800818 break;
819 case 0x1:
820 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700821 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800822 break;
823 case 0x2:
824 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700825 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800826 break;
827 default:
828 action = "unknown";
829 break;
830 }
831
Patrick Williams1bcced02024-08-16 15:20:24 -0400832 std::string firmwareInstanceStr =
833 firmware + " instance: " + std::to_string(instance);
Jason M. Billsdc249272019-04-03 09:58:40 -0700834 std::string message("[firmware update] " + firmwareInstanceStr +
835 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800836
837 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700838 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
839 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
840 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800841 return ipmi::responseSuccess();
842}
843
Patrick Williams1bcced02024-08-16 15:20:24 -0400844ipmi::RspType<uint8_t, std::vector<uint8_t>> ipmiOEMSlotIpmb(
845 ipmi::Context::ptr& ctx, uint6_t reserved1, uint2_t slotNumber,
846 uint3_t baseBoardSlotNum, [[maybe_unused]] uint3_t riserSlotNum,
847 uint2_t reserved2, uint8_t targetAddr, uint8_t netFn, uint8_t cmd,
848 std::optional<std::vector<uint8_t>> writeData)
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530849{
850 if (reserved1 || reserved2)
851 {
852 return ipmi::responseInvalidFieldRequest();
853 }
854
855 boost::system::error_code ec;
856 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
857 std::vector<uint8_t>>;
858 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
859 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
860 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
861 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800862 static_cast<uint8_t>(baseBoardSlotNum), targetAddr, netFn, cmd,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530863 *writeData);
864 if (ec)
865 {
866 phosphor::logging::log<phosphor::logging::level::ERR>(
867 "Failed to call dbus method SlotIpmbRequest");
868 return ipmi::responseUnspecifiedError();
869 }
870
Jason M. Bills48437462025-01-13 14:26:02 -0800871 std::vector<uint8_t> dataReceived{};
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530872 int status = -1;
873 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
874
875 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
876
877 if (status)
878 {
879 phosphor::logging::log<phosphor::logging::level::ERR>(
880 "Failed to get response from SlotIpmbRequest");
881 return ipmi::responseResponseError();
882 }
883 return ipmi::responseSuccess(cc, dataReceived);
884}
885
Vernon Mauerydcff1502022-09-28 11:12:46 -0700886ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t, ipmi_cmd_t,
887 ipmi_request_t request, ipmi_response_t,
888 ipmi_data_len_t dataLen, ipmi_context_t)
Jason M. Bills64796042018-10-03 16:51:55 -0700889{
890 SetPowerRestoreDelayReq* data =
891 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
892 uint16_t delay = 0;
893
894 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
895 {
896 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +0800897 return ipmi::ccReqDataLenInvalid;
Jason M. Bills64796042018-10-03 16:51:55 -0700898 }
899 delay = data->byteMSB;
900 delay = (delay << 8) | data->byteLSB;
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300901 uint64_t val = delay * 1000000;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700902 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -0400903 std::string service =
904 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700905 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300906 powerRestoreDelayIntf, powerRestoreDelayProp, val);
Jason M. Bills64796042018-10-03 16:51:55 -0700907 *dataLen = 0;
908
George Liu24539a42025-07-02 16:58:00 +0800909 return ipmi::ccSuccess;
Jason M. Bills64796042018-10-03 16:51:55 -0700910}
911
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700912static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700913{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700914 static constexpr const char* cpuPresencePathPrefix =
915 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
916 static constexpr const char* cpuPresenceIntf =
917 "xyz.openbmc_project.Inventory.Item";
918 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
919 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
920 try
Jason M. Bills64796042018-10-03 16:51:55 -0700921 {
Patrick Williams1bcced02024-08-16 15:20:24 -0400922 auto service =
923 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700924
925 ipmi::Value result = ipmi::getDbusProperty(
926 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
927 return std::get<bool>(result);
928 }
929 catch (const std::exception& e)
930 {
931 phosphor::logging::log<phosphor::logging::level::INFO>(
932 "Cannot find processor presence",
933 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
934 return false;
935 }
936}
937
Jason M. Billsf284f852023-09-07 15:48:48 -0700938ipmi::RspType<bool, // IERR Reset Enabled
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700939 bool, // ERR2 Reset Enabled
Jason M. Bills51cf3112023-09-07 15:50:23 -0700940 bool, // MCERR Reset Enabled
941 uint5_t, // reserved
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700942 uint8_t, // reserved, returns 0x3F
Jason M. Billsf284f852023-09-07 15:48:48 -0700943 uint6_t, // CPU1 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700944 uint2_t, // CPU1 Status
Jason M. Billsf284f852023-09-07 15:48:48 -0700945 uint6_t, // CPU2 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700946 uint2_t, // CPU2 Status
Jason M. Billsf284f852023-09-07 15:48:48 -0700947 uint6_t, // CPU3 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700948 uint2_t, // CPU3 Status
Jason M. Billsf284f852023-09-07 15:48:48 -0700949 uint6_t, // CPU4 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700950 uint2_t, // CPU4 Status
951 uint8_t // Crashdump Count
952 >
953 ipmiOEMGetProcessorErrConfig()
954{
Jason M. Billsf284f852023-09-07 15:48:48 -0700955 bool resetOnIERR = false;
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700956 bool resetOnERR2 = false;
Jason M. Bills08eb9e52024-07-08 13:09:54 -0700957 bool resetOnMCERR = false;
Jason M. Billsf284f852023-09-07 15:48:48 -0700958 uint6_t cpu1IERRCount = 0;
959 uint6_t cpu2IERRCount = 0;
960 uint6_t cpu3IERRCount = 0;
961 uint6_t cpu4IERRCount = 0;
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700962 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700963 uint2_t cpu1Status = cpuPresent("CPU_1")
964 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
965 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
966 uint2_t cpu2Status = cpuPresent("CPU_2")
967 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
968 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
969 uint2_t cpu3Status = cpuPresent("CPU_3")
970 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
971 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
972 uint2_t cpu4Status = cpuPresent("CPU_4")
973 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
974 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700975
976 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
977 try
978 {
979 auto service = ipmi::getService(*busp, processorErrConfigIntf,
980 processorErrConfigObjPath);
981
982 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
983 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
Jason M. Billsf284f852023-09-07 15:48:48 -0700984 resetOnIERR = std::get<bool>(result.at("ResetOnIERR"));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700985 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
Jason M. Bills08eb9e52024-07-08 13:09:54 -0700986 resetOnMCERR = std::get<bool>(result.at("ResetOnMCERR"));
Jason M. Billsf284f852023-09-07 15:48:48 -0700987 cpu1IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
988 cpu2IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
989 cpu3IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
990 cpu4IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700991 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
992 }
993 catch (const std::exception& e)
994 {
995 phosphor::logging::log<phosphor::logging::level::ERR>(
996 "Failed to fetch processor error config",
997 phosphor::logging::entry("ERROR=%s", e.what()));
998 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700999 }
1000
Patrick Williams1bcced02024-08-16 15:20:24 -04001001 return ipmi::responseSuccess(
Jason M. Bills08eb9e52024-07-08 13:09:54 -07001002 resetOnIERR, resetOnERR2, resetOnMCERR, 0, 0x3F, cpu1IERRCount,
Patrick Williams1bcced02024-08-16 15:20:24 -04001003 cpu1Status, cpu2IERRCount, cpu2Status, cpu3IERRCount, cpu3Status,
1004 cpu4IERRCount, cpu4Status, crashdumpCount);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001005}
Jason M. Bills64796042018-10-03 16:51:55 -07001006
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001007ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
Jason M. Bills08eb9e52024-07-08 13:09:54 -07001008 bool resetOnIERR, bool resetOnERR2, bool resetOnMCERR, uint5_t reserved1,
1009 uint8_t reserved2, std::optional<bool> clearCPUErrorCount,
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001010 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
1011{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +00001012 if (reserved1 || reserved2)
1013 {
1014 return ipmi::responseInvalidFieldRequest();
1015 }
1016
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001017 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -07001018
1019 try
1020 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +00001021 if (reserved3.value_or(0))
1022 {
1023 return ipmi::responseInvalidFieldRequest();
1024 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001025 auto service = ipmi::getService(*busp, processorErrConfigIntf,
1026 processorErrConfigObjPath);
1027 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsf284f852023-09-07 15:48:48 -07001028 processorErrConfigIntf, "ResetOnIERR",
1029 resetOnIERR);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001030 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1031 processorErrConfigIntf, "ResetOnERR2",
1032 resetOnERR2);
Jason M. Bills51cf3112023-09-07 15:50:23 -07001033 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Bills08eb9e52024-07-08 13:09:54 -07001034 processorErrConfigIntf, "ResetOnMCERR",
1035 resetOnMCERR);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001036 if (clearCPUErrorCount.value_or(false))
1037 {
1038 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001039 processorErrConfigIntf, "ErrorCountCPU1",
1040 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001041 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001042 processorErrConfigIntf, "ErrorCountCPU2",
1043 static_cast<uint8_t>(0));
1044 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1045 processorErrConfigIntf, "ErrorCountCPU3",
1046 static_cast<uint8_t>(0));
1047 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1048 processorErrConfigIntf, "ErrorCountCPU4",
1049 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001050 }
1051 if (clearCrashdumpCount.value_or(false))
1052 {
1053 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001054 processorErrConfigIntf, "CrashdumpCount",
1055 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001056 }
Jason M. Bills64796042018-10-03 16:51:55 -07001057 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001058 catch (const std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -07001059 {
Kuiying Wangbc546672018-11-23 15:41:05 +08001060 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001061 "Failed to set processor error config",
1062 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1063 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -07001064 }
1065
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001066 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -07001067}
1068
Vernon Mauerydcff1502022-09-28 11:12:46 -07001069ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
Yong Li703922d2018-11-06 13:25:31 +08001070 ipmi_response_t response,
Vernon Mauerydcff1502022-09-28 11:12:46 -07001071 ipmi_data_len_t dataLen, ipmi_context_t)
Yong Li703922d2018-11-06 13:25:31 +08001072{
1073 GetOEMShutdownPolicyRes* resp =
1074 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
1075
1076 if (*dataLen != 0)
1077 {
1078 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +08001079 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +08001080 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +08001081 return ipmi::ccReqDataLenInvalid;
Yong Li703922d2018-11-06 13:25:31 +08001082 }
1083
1084 *dataLen = 0;
1085
1086 try
1087 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001088 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001089 std::string service =
1090 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001091 Value variant = getDbusProperty(
1092 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
1093 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +08001094
1095 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1096 convertPolicyFromString(std::get<std::string>(variant)) ==
1097 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1098 NoShutdownOnOCOT)
1099 {
1100 resp->policy = 0;
1101 }
1102 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1103 convertPolicyFromString(std::get<std::string>(variant)) ==
1104 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1105 Policy::ShutdownOnOCOT)
1106 {
1107 resp->policy = 1;
1108 }
1109 else
1110 {
1111 phosphor::logging::log<phosphor::logging::level::ERR>(
1112 "oem_set_shutdown_policy: invalid property!",
1113 phosphor::logging::entry(
1114 "PROP=%s", std::get<std::string>(variant).c_str()));
George Liu24539a42025-07-02 16:58:00 +08001115 return ipmi::ccUnspecifiedError;
Yong Li0669d192019-05-06 14:01:46 +08001116 }
Yong Li703922d2018-11-06 13:25:31 +08001117 // TODO needs to check if it is multi-node products,
1118 // policy is only supported on node 3/4
1119 resp->policySupport = shutdownPolicySupported;
1120 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001121 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001122 {
1123 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
George Liu24539a42025-07-02 16:58:00 +08001124 return ipmi::ccUnspecifiedError;
Yong Li703922d2018-11-06 13:25:31 +08001125 }
1126
1127 *dataLen = sizeof(GetOEMShutdownPolicyRes);
George Liu24539a42025-07-02 16:58:00 +08001128 return ipmi::ccSuccess;
Yong Li703922d2018-11-06 13:25:31 +08001129}
1130
Vernon Mauerydcff1502022-09-28 11:12:46 -07001131ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t, ipmi_cmd_t,
1132 ipmi_request_t request, ipmi_response_t,
1133 ipmi_data_len_t dataLen, ipmi_context_t)
Yong Li703922d2018-11-06 13:25:31 +08001134{
1135 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +08001136 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
1137 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1138 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +08001139
1140 // TODO needs to check if it is multi-node products,
1141 // policy is only supported on node 3/4
1142 if (*dataLen != 1)
1143 {
1144 phosphor::logging::log<phosphor::logging::level::ERR>(
1145 "oem_set_shutdown_policy: invalid input len!");
1146 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +08001147 return ipmi::ccReqDataLenInvalid;
Yong Li703922d2018-11-06 13:25:31 +08001148 }
1149
1150 *dataLen = 0;
1151 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
1152 {
1153 phosphor::logging::log<phosphor::logging::level::ERR>(
1154 "oem_set_shutdown_policy: invalid input!");
George Liu24539a42025-07-02 16:58:00 +08001155 return ipmi::ccInvalidFieldRequest;
Yong Li703922d2018-11-06 13:25:31 +08001156 }
1157
Yong Li0669d192019-05-06 14:01:46 +08001158 if (*req == noShutdownOnOCOT)
1159 {
1160 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1161 Policy::NoShutdownOnOCOT;
1162 }
1163 else
1164 {
1165 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1166 Policy::ShutdownOnOCOT;
1167 }
1168
Yong Li703922d2018-11-06 13:25:31 +08001169 try
1170 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001171 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001172 std::string service =
1173 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +08001174 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001175 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +08001176 oemShutdownPolicyObjPathProp,
1177 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +08001178 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001179 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001180 {
1181 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
George Liu24539a42025-07-02 16:58:00 +08001182 return ipmi::ccUnspecifiedError;
Yong Li703922d2018-11-06 13:25:31 +08001183 }
1184
George Liu24539a42025-07-02 16:58:00 +08001185 return ipmi::ccSuccess;
Yong Li703922d2018-11-06 13:25:31 +08001186}
1187
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301188/** @brief implementation for check the DHCP or not in IPv4
1189 * @param[in] Channel - Channel number
1190 * @returns true or false.
1191 */
1192static bool isDHCPEnabled(uint8_t Channel)
1193{
1194 try
1195 {
1196 auto ethdevice = getChannelName(Channel);
1197 if (ethdevice.empty())
1198 {
1199 return false;
1200 }
1201 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001202 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001203 auto ethernetObj =
1204 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001205 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301206 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001207 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301208 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1209 {
1210 return true;
1211 }
1212 else
1213 {
1214 return false;
1215 }
1216 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001217 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301218 {
1219 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1220 return true;
1221 }
1222}
1223
1224/** @brief implementes for check the DHCP or not in IPv6
1225 * @param[in] Channel - Channel number
1226 * @returns true or false.
1227 */
1228static bool isDHCPIPv6Enabled(uint8_t Channel)
1229{
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301230 try
1231 {
1232 auto ethdevice = getChannelName(Channel);
1233 if (ethdevice.empty())
1234 {
1235 return false;
1236 }
1237 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001238 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001239 auto objectInfo =
1240 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001241 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301242 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001243 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301244 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1245 {
1246 return true;
1247 }
1248 else
1249 {
1250 return false;
1251 }
1252 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001253 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301254 {
1255 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1256 return true;
1257 }
1258}
1259
1260/** @brief implementes the creating of default new user
1261 * @param[in] userName - new username in 16 bytes.
1262 * @param[in] userPassword - new password in 20 bytes
1263 * @returns ipmi completion code.
1264 */
1265ipmi::RspType<> ipmiOEMSetUser2Activation(
1266 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001267 const SecureBuffer& userPassword)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301268{
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001269 if (userPassword.size() != ipmi::maxIpmi20PasswordSize)
1270 {
1271 return ipmi::responseReqDataLenInvalid();
1272 }
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301273 bool userState = false;
1274 // Check for System Interface not exist and LAN should be static
1275 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1276 {
Manish Baing440f62b2021-07-15 22:00:37 +00001277 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301278 try
1279 {
1280 getChannelInfo(channel, chInfo);
1281 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001282 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301283 {
1284 phosphor::logging::log<phosphor::logging::level::ERR>(
1285 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1286 phosphor::logging::entry("MSG: %s", e.description()));
1287 return ipmi::response(ipmi::ccUnspecifiedError);
1288 }
1289 if (chInfo.mediumType ==
1290 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1291 {
1292 phosphor::logging::log<phosphor::logging::level::ERR>(
1293 "ipmiOEMSetUser2Activation: system interface exist .");
1294 return ipmi::response(ipmi::ccCommandNotAvailable);
1295 }
1296 else
1297 {
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301298 if (chInfo.mediumType ==
1299 static_cast<uint8_t>(EChannelMediumType::lan8032))
1300 {
1301 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1302 {
1303 phosphor::logging::log<phosphor::logging::level::ERR>(
1304 "ipmiOEMSetUser2Activation: DHCP enabled .");
1305 return ipmi::response(ipmi::ccCommandNotAvailable);
1306 }
1307 }
1308 }
1309 }
1310 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1311 if (ipmi::ccSuccess ==
1312 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1313 {
1314 if (enabledUsers > 1)
1315 {
1316 phosphor::logging::log<phosphor::logging::level::ERR>(
1317 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1318 return ipmi::response(ipmi::ccCommandNotAvailable);
1319 }
1320 // Check the user 2 is enabled or not
1321 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1322 if (userState == true)
1323 {
1324 phosphor::logging::log<phosphor::logging::level::ERR>(
1325 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1326 return ipmi::response(ipmi::ccCommandNotAvailable);
1327 }
1328 }
1329 else
1330 {
1331 return ipmi::response(ipmi::ccUnspecifiedError);
1332 }
1333
1334#if BYTE_ORDER == LITTLE_ENDIAN
1335 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1336#endif
1337#if BYTE_ORDER == BIG_ENDIAN
1338 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1339#endif
1340
Vernon Mauery037cabd2020-05-14 12:16:01 -07001341 // ipmiUserSetUserName correctly handles char*, possibly non-null
1342 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001343 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1344 sizeof(userName));
1345 const std::string userNameRaw(
1346 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001347
Vernon Mauery037cabd2020-05-14 12:16:01 -07001348 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301349 {
1350 if (ipmi::ccSuccess ==
1351 ipmiUserSetUserPassword(
1352 ipmiDefaultUserId,
1353 reinterpret_cast<const char*>(userPassword.data())))
1354 {
1355 if (ipmi::ccSuccess ==
1356 ipmiUserSetPrivilegeAccess(
1357 ipmiDefaultUserId,
1358 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1359 privAccess, true))
1360 {
1361 phosphor::logging::log<phosphor::logging::level::INFO>(
1362 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001363
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301364 return ipmi::responseSuccess();
1365 }
1366 }
1367 // we need to delete the default user id which added in this command as
1368 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001369 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301370 phosphor::logging::log<phosphor::logging::level::ERR>(
1371 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1372 }
1373 else
1374 {
1375 phosphor::logging::log<phosphor::logging::level::ERR>(
1376 "ipmiOEMSetUser2Activation: Setting username failed.");
1377 }
1378
1379 return ipmi::response(ipmi::ccCommandNotAvailable);
1380}
1381
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301382/** @brief implementes executing the linux command
1383 * @param[in] linux command
1384 * @returns status
1385 */
1386
1387static uint8_t executeCmd(const char* path)
1388{
Chau Lyc4b3d302025-08-05 06:51:14 +00001389 boost::process::v1::child execProg(path);
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301390 execProg.wait();
1391
1392 int retCode = execProg.exit_code();
1393 if (retCode)
1394 {
1395 return ipmi::ccUnspecifiedError;
1396 }
1397 return ipmi::ccSuccess;
1398}
1399
1400/** @brief implementes ASD Security event logging
1401 * @param[in] Event message string
1402 * @param[in] Event Severity
1403 * @returns status
1404 */
1405
1406static void atScaleDebugEventlog(std::string msg, int severity)
1407{
1408 std::string eventStr = "OpenBMC.0.1." + msg;
1409 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1410 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1411 eventStr.c_str(), NULL);
1412}
1413
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301414/** @brief implementes setting password for special user
1415 * @param[in] specialUserIndex
1416 * @param[in] userPassword - new password in 20 bytes
1417 * @returns ipmi completion code.
1418 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07001419ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr& ctx,
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301420 uint8_t specialUserIndex,
1421 std::vector<uint8_t> userPassword)
1422{
1423 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301424 ipmi_ret_t status = ipmi::ccSuccess;
1425
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301426 try
1427 {
1428 getChannelInfo(ctx->channel, chInfo);
1429 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001430 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301431 {
1432 phosphor::logging::log<phosphor::logging::level::ERR>(
1433 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1434 phosphor::logging::entry("MSG: %s", e.description()));
1435 return ipmi::responseUnspecifiedError();
1436 }
1437 if (chInfo.mediumType !=
1438 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1439 {
1440 phosphor::logging::log<phosphor::logging::level::ERR>(
1441 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1442 "interface");
1443 return ipmi::responseCommandNotAvailable();
1444 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301445
1446 // 0 for root user and 1 for AtScaleDebug is allowed
1447 if (specialUserIndex >
1448 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301449 {
1450 phosphor::logging::log<phosphor::logging::level::ERR>(
1451 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1452 return ipmi::responseParmOutOfRange();
1453 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301454 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301455 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301456 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001457 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301458 if (userPassword.size() < minPasswordSizeRequired ||
1459 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1460 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001461 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301462 return ipmi::responseReqDataLenInvalid();
1463 }
1464 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1465 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001466 // Clear sensitive data
1467 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301468 if (specialUserIndex ==
1469 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1470 {
1471 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1472
1473 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1474 }
1475 else
1476 {
1477 status = ipmiSetSpecialUserPassword("root", passwd);
1478 }
1479 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301480 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301481 else
1482 {
1483 if (specialUserIndex ==
1484 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1485 {
1486 status = executeCmd("passwd -d root");
1487 }
1488 else
1489 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301490 status = executeCmd("passwd -d asdbg");
1491
1492 if (status == 0)
1493 {
1494 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1495 LOG_INFO);
1496 }
1497 }
1498 return ipmi::response(status);
1499 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301500}
1501
Kuiying Wang45f04982018-12-26 09:23:08 +08001502namespace ledAction
1503{
1504using namespace sdbusplus::xyz::openbmc_project::Led::server;
1505std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001506 {Physical::Action::Off, 0},
1507 {Physical::Action::On, 2},
1508 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001509
1510std::map<uint8_t, std::string> offsetObjPath = {
1511 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1512
1513} // namespace ledAction
1514
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001515int8_t getLEDState(sdbusplus::bus_t& bus, const std::string& intf,
Kuiying Wang45f04982018-12-26 09:23:08 +08001516 const std::string& objPath, uint8_t& state)
1517{
1518 try
1519 {
1520 std::string service = getService(bus, intf, objPath);
Patrick Williams1bcced02024-08-16 15:20:24 -04001521 Value stateValue =
1522 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001523 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001524 state = ledAction::actionDbusToIpmi.at(
1525 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1526 convertActionFromString(strState));
1527 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001528 catch (const sdbusplus::exception_t& e)
Kuiying Wang45f04982018-12-26 09:23:08 +08001529 {
1530 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1531 return -1;
1532 }
1533 return 0;
1534}
1535
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001536ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001537{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001538 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001539 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001540 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001541 for (auto it = ledAction::offsetObjPath.begin();
1542 it != ledAction::offsetObjPath.end(); ++it)
1543 {
1544 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001545 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001546 {
1547 phosphor::logging::log<phosphor::logging::level::ERR>(
1548 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001549 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001550 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001551 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001552 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001553 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001554}
1555
Patrick Williams1bcced02024-08-16 15:20:24 -04001556ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(
1557 ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t request, ipmi_response_t response,
1558 ipmi_data_len_t dataLen, ipmi_context_t)
Yong Li23737fe2019-02-19 08:49:55 +08001559{
1560 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1561 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1562
1563 if (*dataLen == 0)
1564 {
1565 phosphor::logging::log<phosphor::logging::level::ERR>(
1566 "CfgHostSerial: invalid input len!",
1567 phosphor::logging::entry("LEN=%d", *dataLen));
George Liu24539a42025-07-02 16:58:00 +08001568 return ipmi::ccReqDataLenInvalid;
Yong Li23737fe2019-02-19 08:49:55 +08001569 }
1570
1571 switch (req->command)
1572 {
1573 case getHostSerialCfgCmd:
1574 {
1575 if (*dataLen != 1)
1576 {
1577 phosphor::logging::log<phosphor::logging::level::ERR>(
1578 "CfgHostSerial: invalid input len!");
1579 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +08001580 return ipmi::ccReqDataLenInvalid;
Yong Li23737fe2019-02-19 08:49:55 +08001581 }
1582
1583 *dataLen = 0;
1584
Chau Lyc4b3d302025-08-05 06:51:14 +00001585 boost::process::v1::ipstream is;
Yong Li23737fe2019-02-19 08:49:55 +08001586 std::vector<std::string> data;
1587 std::string line;
Chau Lyc4b3d302025-08-05 06:51:14 +00001588 boost::process::v1::child c1(fwGetEnvCmd, "-n",
1589 fwHostSerailCfgEnvName,
1590 boost::process::v1::std_out > is);
Yong Li23737fe2019-02-19 08:49:55 +08001591
1592 while (c1.running() && std::getline(is, line) && !line.empty())
1593 {
1594 data.push_back(line);
1595 }
1596
1597 c1.wait();
1598 if (c1.exit_code())
1599 {
1600 phosphor::logging::log<phosphor::logging::level::ERR>(
1601 "CfgHostSerial:: error on execute",
1602 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1603 // Using the default value
1604 *resp = 0;
1605 }
1606 else
1607 {
1608 if (data.size() != 1)
1609 {
1610 phosphor::logging::log<phosphor::logging::level::ERR>(
1611 "CfgHostSerial:: error on read env");
George Liu24539a42025-07-02 16:58:00 +08001612 return ipmi::ccUnspecifiedError;
Yong Li23737fe2019-02-19 08:49:55 +08001613 }
1614 try
1615 {
1616 unsigned long tmp = std::stoul(data[0]);
1617 if (tmp > std::numeric_limits<uint8_t>::max())
1618 {
1619 throw std::out_of_range("Out of range");
1620 }
1621 *resp = static_cast<uint8_t>(tmp);
1622 }
1623 catch (const std::invalid_argument& e)
1624 {
1625 phosphor::logging::log<phosphor::logging::level::ERR>(
1626 "invalid config ",
1627 phosphor::logging::entry("ERR=%s", e.what()));
George Liu24539a42025-07-02 16:58:00 +08001628 return ipmi::ccUnspecifiedError;
Yong Li23737fe2019-02-19 08:49:55 +08001629 }
1630 catch (const std::out_of_range& e)
1631 {
1632 phosphor::logging::log<phosphor::logging::level::ERR>(
1633 "out_of_range config ",
1634 phosphor::logging::entry("ERR=%s", e.what()));
George Liu24539a42025-07-02 16:58:00 +08001635 return ipmi::ccUnspecifiedError;
Yong Li23737fe2019-02-19 08:49:55 +08001636 }
1637 }
1638
1639 *dataLen = 1;
1640 break;
1641 }
1642 case setHostSerialCfgCmd:
1643 {
1644 if (*dataLen != sizeof(CfgHostSerialReq))
1645 {
1646 phosphor::logging::log<phosphor::logging::level::ERR>(
1647 "CfgHostSerial: invalid input len!");
1648 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +08001649 return ipmi::ccReqDataLenInvalid;
Yong Li23737fe2019-02-19 08:49:55 +08001650 }
1651
1652 *dataLen = 0;
1653
1654 if (req->parameter > HostSerialCfgParamMax)
1655 {
1656 phosphor::logging::log<phosphor::logging::level::ERR>(
1657 "CfgHostSerial: invalid input!");
George Liu24539a42025-07-02 16:58:00 +08001658 return ipmi::ccInvalidFieldRequest;
Yong Li23737fe2019-02-19 08:49:55 +08001659 }
1660
Chau Lyc4b3d302025-08-05 06:51:14 +00001661 boost::process::v1::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1662 std::to_string(req->parameter));
Yong Li23737fe2019-02-19 08:49:55 +08001663
1664 c1.wait();
1665 if (c1.exit_code())
1666 {
1667 phosphor::logging::log<phosphor::logging::level::ERR>(
1668 "CfgHostSerial:: error on execute",
1669 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
George Liu24539a42025-07-02 16:58:00 +08001670 return ipmi::ccUnspecifiedError;
Yong Li23737fe2019-02-19 08:49:55 +08001671 }
1672 break;
1673 }
1674 default:
1675 phosphor::logging::log<phosphor::logging::level::ERR>(
1676 "CfgHostSerial: invalid input!");
1677 *dataLen = 0;
George Liu24539a42025-07-02 16:58:00 +08001678 return ipmi::ccInvalidFieldRequest;
Yong Li23737fe2019-02-19 08:49:55 +08001679 }
1680
George Liu24539a42025-07-02 16:58:00 +08001681 return ipmi::ccSuccess;
Yong Li23737fe2019-02-19 08:49:55 +08001682}
1683
James Feist91244a62019-02-19 15:04:54 -08001684constexpr const char* thermalModeInterface =
1685 "xyz.openbmc_project.Control.ThermalMode";
1686constexpr const char* thermalModePath =
1687 "/xyz/openbmc_project/control/thermal_mode";
1688
1689bool getFanProfileInterface(
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001690 sdbusplus::bus_t& bus,
Jason M. Bills0748c692022-09-08 15:34:08 -07001691 boost::container::flat_map<std::string, ipmi::DbusVariant>& resp)
James Feist91244a62019-02-19 15:04:54 -08001692{
1693 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1694 "GetAll");
1695 call.append(thermalModeInterface);
1696 try
1697 {
1698 auto data = bus.call(call);
1699 data.read(resp);
1700 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001701 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001702 {
1703 phosphor::logging::log<phosphor::logging::level::ERR>(
1704 "getFanProfileInterface: can't get thermal mode!",
1705 phosphor::logging::entry("ERR=%s", e.what()));
1706 return false;
1707 }
1708 return true;
1709}
1710
anil kumar appanaf945eee2019-09-25 23:29:11 +00001711/**@brief implements the OEM set fan config.
1712 * @param selectedFanProfile - fan profile to enable
1713 * @param reserved1
1714 * @param performanceMode - Performance/Acoustic mode
1715 * @param reserved2
1716 * @param setPerformanceMode - set Performance/Acoustic mode
1717 * @param setFanProfile - set fan profile
1718 *
1719 * @return IPMI completion code.
1720 **/
Vernon Mauerydcff1502022-09-28 11:12:46 -07001721ipmi::RspType<> ipmiOEMSetFanConfig(
1722 [[maybe_unused]] uint8_t selectedFanProfile, uint2_t reserved1,
1723 bool performanceMode, uint3_t reserved2, bool setPerformanceMode,
1724 [[maybe_unused]] bool setFanProfile, std::optional<uint8_t> dimmGroupId,
1725 [[maybe_unused]] std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001726{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001727 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001728 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001729 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001730 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301731
1732 if (dimmGroupId)
1733 {
1734 if (*dimmGroupId >= maxCPUNum)
1735 {
1736 return ipmi::responseInvalidFieldRequest();
1737 }
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001738 if (!cpuPresent("cpu" + std::to_string(*dimmGroupId)))
Joshi-Mansi619186d2020-01-27 19:16:03 +05301739 {
1740 return ipmi::responseInvalidFieldRequest();
1741 }
1742 }
1743
James Feist91244a62019-02-19 15:04:54 -08001744 // todo: tell bios to only send first 2 bytes
Jason M. Bills0748c692022-09-08 15:34:08 -07001745 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001746 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1747 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001748 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001749 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001750 }
1751
1752 std::vector<std::string>* supported =
1753 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1754 if (supported == nullptr)
1755 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001756 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001757 }
1758 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001759 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001760 {
James Feist91244a62019-02-19 15:04:54 -08001761 if (performanceMode)
1762 {
James Feist91244a62019-02-19 15:04:54 -08001763 if (std::find(supported->begin(), supported->end(),
1764 "Performance") != supported->end())
1765 {
1766 mode = "Performance";
1767 }
1768 }
1769 else
1770 {
James Feist91244a62019-02-19 15:04:54 -08001771 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1772 supported->end())
1773 {
1774 mode = "Acoustic";
1775 }
1776 }
1777 if (mode.empty())
1778 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001779 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001780 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001781
1782 try
1783 {
1784 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1785 thermalModeInterface, "Current", mode);
1786 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001787 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001788 {
1789 phosphor::logging::log<phosphor::logging::level::ERR>(
1790 "ipmiOEMSetFanConfig: can't set thermal mode!",
1791 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1792 return ipmi::responseResponseError();
1793 }
James Feist91244a62019-02-19 15:04:54 -08001794 }
1795
anil kumar appanaf945eee2019-09-25 23:29:11 +00001796 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001797}
1798
James Feist5b693632019-07-09 09:06:09 -07001799ipmi::RspType<uint8_t, // profile support map
1800 uint8_t, // fan control profile enable
1801 uint8_t, // flags
1802 uint32_t // dimm presence bit map
1803 >
1804 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001805{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301806 if (dimmGroupId >= maxCPUNum)
1807 {
1808 return ipmi::responseInvalidFieldRequest();
1809 }
1810
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001811 bool cpuStatus = cpuPresent("cpu" + std::to_string(dimmGroupId));
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301812
1813 if (!cpuStatus)
1814 {
1815 return ipmi::responseInvalidFieldRequest();
1816 }
1817
Jason M. Bills0748c692022-09-08 15:34:08 -07001818 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
James Feist91244a62019-02-19 15:04:54 -08001819
Vernon Mauery15419dd2019-05-24 09:40:30 -07001820 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1821 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001822 {
James Feist5b693632019-07-09 09:06:09 -07001823 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001824 }
1825
1826 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1827
1828 if (current == nullptr)
1829 {
1830 phosphor::logging::log<phosphor::logging::level::ERR>(
1831 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001832 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001833 }
1834 bool performance = (*current == "Performance");
1835
James Feist5b693632019-07-09 09:06:09 -07001836 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001837 if (performance)
1838 {
James Feist5b693632019-07-09 09:06:09 -07001839 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001840 }
1841
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001842 constexpr uint8_t fanControlDefaultProfile = 0x80;
1843 constexpr uint8_t fanControlProfileState = 0x00;
1844 constexpr uint32_t dimmPresenceBitmap = 0x00;
1845
1846 return ipmi::responseSuccess(fanControlDefaultProfile,
1847 fanControlProfileState, flags,
1848 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001849}
James Feist5f957ca2019-03-14 15:33:55 -07001850constexpr const char* cfmLimitSettingPath =
1851 "/xyz/openbmc_project/control/cfm_limit";
1852constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001853constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001854constexpr const size_t legacyPCHSensorNumber = 0x22;
1855constexpr const char* exitAirPathName = "Exit_Air";
1856constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001857constexpr const char* pidConfigurationIface =
1858 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001859
James Feist09f6b602019-08-08 11:30:03 -07001860static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001861{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001862 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001863 auto method =
1864 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1865 "/xyz/openbmc_project/object_mapper",
1866 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001867
James Feistacc8a4e2019-04-02 14:23:57 -07001868 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001869 std::string path;
1870 GetSubTreeType resp;
1871 try
1872 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001873 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001874 reply.read(resp);
1875 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001876 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001877 {
1878 phosphor::logging::log<phosphor::logging::level::ERR>(
1879 "ipmiOEMGetFscParameter: mapper error");
1880 };
Patrick Williams1bcced02024-08-16 15:20:24 -04001881 auto config =
1882 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1883 return pair.first.find(name) != std::string::npos;
1884 });
James Feistfaa4f222019-03-21 16:21:55 -07001885 if (config != resp.end())
1886 {
1887 path = std::move(config->first);
1888 }
1889 return path;
1890}
James Feist5f957ca2019-03-14 15:33:55 -07001891
James Feistacc8a4e2019-04-02 14:23:57 -07001892// flat map to make alphabetical
1893static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1894{
1895 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001896 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001897 auto method =
1898 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1899 "/xyz/openbmc_project/object_mapper",
1900 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001901
1902 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1903 GetSubTreeType resp;
1904
1905 try
1906 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001907 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001908 reply.read(resp);
1909 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001910 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001911 {
1912 phosphor::logging::log<phosphor::logging::level::ERR>(
1913 "getFanConfigPaths: mapper error");
1914 };
1915 for (const auto& [path, objects] : resp)
1916 {
1917 if (objects.empty())
1918 {
1919 continue; // should be impossible
1920 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001921
1922 try
1923 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001924 ret.emplace(path,
1925 getAllDbusProperties(*dbus, objects[0].first, path,
1926 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001927 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001928 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001929 {
1930 phosphor::logging::log<phosphor::logging::level::ERR>(
1931 "getPidConfigs: can't get DbusProperties!",
1932 phosphor::logging::entry("ERR=%s", e.what()));
1933 }
James Feistacc8a4e2019-04-02 14:23:57 -07001934 }
1935 return ret;
1936}
1937
1938ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1939{
1940 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1941 if (data.empty())
1942 {
1943 return ipmi::responseResponseError();
1944 }
1945 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1946 for (const auto& [_, pid] : data)
1947 {
1948 auto findClass = pid.find("Class");
1949 if (findClass == pid.end())
1950 {
1951 phosphor::logging::log<phosphor::logging::level::ERR>(
1952 "ipmiOEMGetFscParameter: found illegal pid "
1953 "configurations");
1954 return ipmi::responseResponseError();
1955 }
1956 std::string type = std::get<std::string>(findClass->second);
1957 if (type == "fan")
1958 {
1959 auto findOutLimit = pid.find("OutLimitMin");
1960 if (findOutLimit == pid.end())
1961 {
1962 phosphor::logging::log<phosphor::logging::level::ERR>(
1963 "ipmiOEMGetFscParameter: found illegal pid "
1964 "configurations");
1965 return ipmi::responseResponseError();
1966 }
1967 // get the min out of all the offsets
1968 minOffset = std::min(
1969 minOffset,
1970 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1971 }
1972 }
1973 if (minOffset == std::numeric_limits<uint8_t>::max())
1974 {
1975 phosphor::logging::log<phosphor::logging::level::ERR>(
1976 "ipmiOEMGetFscParameter: found no fan configurations!");
1977 return ipmi::responseResponseError();
1978 }
1979
1980 return ipmi::responseSuccess(minOffset);
1981}
1982
1983ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1984{
Manish Baingbaa579f2021-10-08 22:30:32 +00001985 constexpr uint8_t maxFanSpeedOffset = 100;
1986 if (offset > maxFanSpeedOffset)
1987 {
1988 phosphor::logging::log<phosphor::logging::level::ERR>(
1989 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1990 return ipmi::responseInvalidFieldRequest();
1991 }
James Feistacc8a4e2019-04-02 14:23:57 -07001992 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1993 if (data.empty())
1994 {
James Feistacc8a4e2019-04-02 14:23:57 -07001995 phosphor::logging::log<phosphor::logging::level::ERR>(
1996 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1997 return ipmi::responseResponseError();
1998 }
1999
Vernon Mauery15419dd2019-05-24 09:40:30 -07002000 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002001 bool found = false;
2002 for (const auto& [path, pid] : data)
2003 {
2004 auto findClass = pid.find("Class");
2005 if (findClass == pid.end())
2006 {
James Feistacc8a4e2019-04-02 14:23:57 -07002007 phosphor::logging::log<phosphor::logging::level::ERR>(
2008 "ipmiOEMSetFanSpeedOffset: found illegal pid "
2009 "configurations");
2010 return ipmi::responseResponseError();
2011 }
2012 std::string type = std::get<std::string>(findClass->second);
2013 if (type == "fan")
2014 {
2015 auto findOutLimit = pid.find("OutLimitMin");
2016 if (findOutLimit == pid.end())
2017 {
James Feistacc8a4e2019-04-02 14:23:57 -07002018 phosphor::logging::log<phosphor::logging::level::ERR>(
2019 "ipmiOEMSetFanSpeedOffset: found illegal pid "
2020 "configurations");
2021 return ipmi::responseResponseError();
2022 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07002023 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07002024 path, pidConfigurationIface, "OutLimitMin",
2025 static_cast<double>(offset));
2026 found = true;
2027 }
2028 }
2029 if (!found)
2030 {
2031 phosphor::logging::log<phosphor::logging::level::ERR>(
2032 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
2033 return ipmi::responseResponseError();
2034 }
2035
2036 return ipmi::responseSuccess();
2037}
2038
2039ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
2040 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07002041{
2042 constexpr const size_t disableLimiting = 0x0;
2043
Vernon Mauery15419dd2019-05-24 09:40:30 -07002044 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002045 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002046 {
James Feist09f6b602019-08-08 11:30:03 -07002047 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07002048 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07002049 {
James Feist09f6b602019-08-08 11:30:03 -07002050 pathName = exitAirPathName;
2051 }
2052 else if (param1 == legacyPCHSensorNumber)
2053 {
2054 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07002055 }
2056 else
2057 {
James Feistacc8a4e2019-04-02 14:23:57 -07002058 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002059 }
James Feist09f6b602019-08-08 11:30:03 -07002060 std::string path = getConfigPath(pathName);
2061 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
2062 pidConfigurationIface, "SetPoint",
2063 static_cast<double>(param2));
2064 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07002065 }
James Feistacc8a4e2019-04-02 14:23:57 -07002066 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002067 {
James Feistacc8a4e2019-04-02 14:23:57 -07002068 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07002069
2070 // must be greater than 50 based on eps
2071 if (cfm < 50 && cfm != disableLimiting)
2072 {
James Feistacc8a4e2019-04-02 14:23:57 -07002073 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002074 }
2075
2076 try
2077 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002078 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07002079 cfmLimitIface, "Limit",
2080 static_cast<double>(cfm));
2081 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002082 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002083 {
2084 phosphor::logging::log<phosphor::logging::level::ERR>(
2085 "ipmiOEMSetFscParameter: can't set cfm setting!",
2086 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002087 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002088 }
James Feistacc8a4e2019-04-02 14:23:57 -07002089 return ipmi::responseSuccess();
2090 }
2091 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2092 {
James Feistacc8a4e2019-04-02 14:23:57 -07002093 uint8_t requestedDomainMask = param1;
2094 boost::container::flat_map data = getPidConfigs();
2095 if (data.empty())
2096 {
James Feistacc8a4e2019-04-02 14:23:57 -07002097 phosphor::logging::log<phosphor::logging::level::ERR>(
2098 "ipmiOEMSetFscParameter: found no pid configurations!");
2099 return ipmi::responseResponseError();
2100 }
2101 size_t count = 0;
2102 for (const auto& [path, pid] : data)
2103 {
2104 auto findClass = pid.find("Class");
2105 if (findClass == pid.end())
2106 {
James Feistacc8a4e2019-04-02 14:23:57 -07002107 phosphor::logging::log<phosphor::logging::level::ERR>(
2108 "ipmiOEMSetFscParameter: found illegal pid "
2109 "configurations");
2110 return ipmi::responseResponseError();
2111 }
2112 std::string type = std::get<std::string>(findClass->second);
2113 if (type == "fan")
2114 {
2115 if (requestedDomainMask & (1 << count))
2116 {
2117 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002118 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07002119 pidConfigurationIface, "OutLimitMax",
2120 static_cast<double>(param2));
2121 }
2122 count++;
2123 }
2124 }
2125 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07002126 }
2127 else
2128 {
2129 // todo other command parts possibly
2130 // tcontrol is handled in peci now
2131 // fan speed offset not implemented yet
2132 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002133 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002134 }
2135}
2136
James Feistacc8a4e2019-04-02 14:23:57 -07002137ipmi::RspType<
2138 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2139 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002140{
James Feist09f6b602019-08-08 11:30:03 -07002141 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002142
Vernon Mauery15419dd2019-05-24 09:40:30 -07002143 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002144 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002145 {
James Feistacc8a4e2019-04-02 14:23:57 -07002146 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002147 {
James Feistacc8a4e2019-04-02 14:23:57 -07002148 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002149 }
2150
James Feist09f6b602019-08-08 11:30:03 -07002151 std::string pathName;
2152
2153 if (*param == legacyExitAirSensorNumber)
2154 {
2155 pathName = exitAirPathName;
2156 }
2157 else if (*param == legacyPCHSensorNumber)
2158 {
2159 pathName = pchPathName;
2160 }
2161 else
James Feistfaa4f222019-03-21 16:21:55 -07002162 {
James Feistacc8a4e2019-04-02 14:23:57 -07002163 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002164 }
James Feist09f6b602019-08-08 11:30:03 -07002165
2166 uint8_t setpoint = legacyDefaultSetpoint;
2167 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002168 if (path.size())
2169 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002170 Value val = ipmi::getDbusProperty(
2171 *dbus, "xyz.openbmc_project.EntityManager", path,
2172 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002173 setpoint = std::floor(std::get<double>(val) + 0.5);
2174 }
2175
2176 // old implementation used to return the "default" and current, we
2177 // don't make the default readily available so just make both the
2178 // same
James Feistfaa4f222019-03-21 16:21:55 -07002179
James Feistacc8a4e2019-04-02 14:23:57 -07002180 return ipmi::responseSuccess(
2181 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002182 }
James Feistacc8a4e2019-04-02 14:23:57 -07002183 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2184 {
2185 constexpr const size_t maxDomainCount = 8;
2186
2187 if (!param)
2188 {
2189 return ipmi::responseReqDataLenInvalid();
2190 }
2191 uint8_t requestedDomain = *param;
2192 if (requestedDomain >= maxDomainCount)
2193 {
2194 return ipmi::responseInvalidFieldRequest();
2195 }
2196
2197 boost::container::flat_map data = getPidConfigs();
2198 if (data.empty())
2199 {
2200 phosphor::logging::log<phosphor::logging::level::ERR>(
2201 "ipmiOEMGetFscParameter: found no pid configurations!");
2202 return ipmi::responseResponseError();
2203 }
2204 size_t count = 0;
2205 for (const auto& [_, pid] : data)
2206 {
2207 auto findClass = pid.find("Class");
2208 if (findClass == pid.end())
2209 {
2210 phosphor::logging::log<phosphor::logging::level::ERR>(
2211 "ipmiOEMGetFscParameter: found illegal pid "
2212 "configurations");
2213 return ipmi::responseResponseError();
2214 }
2215 std::string type = std::get<std::string>(findClass->second);
2216 if (type == "fan")
2217 {
2218 if (requestedDomain == count)
2219 {
2220 auto findOutLimit = pid.find("OutLimitMax");
2221 if (findOutLimit == pid.end())
2222 {
2223 phosphor::logging::log<phosphor::logging::level::ERR>(
2224 "ipmiOEMGetFscParameter: found illegal pid "
2225 "configurations");
2226 return ipmi::responseResponseError();
2227 }
2228
2229 return ipmi::responseSuccess(
2230 static_cast<uint8_t>(std::floor(
2231 std::get<double>(findOutLimit->second) + 0.5)));
2232 }
2233 else
2234 {
2235 count++;
2236 }
2237 }
2238 }
2239
2240 return ipmi::responseInvalidFieldRequest();
2241 }
2242 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002243 {
James Feist5f957ca2019-03-14 15:33:55 -07002244 /*
2245 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002246 previous behavior didn't seem to prevent this, ignore the check for
2247 now.
James Feist5f957ca2019-03-14 15:33:55 -07002248
James Feistacc8a4e2019-04-02 14:23:57 -07002249 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002250 {
2251 phosphor::logging::log<phosphor::logging::level::ERR>(
2252 "ipmiOEMGetFscParameter: invalid input len!");
George Liu24539a42025-07-02 16:58:00 +08002253 return ipmi::ccReqDataLenInvalid;
James Feist5f957ca2019-03-14 15:33:55 -07002254 }
2255 */
2256 Value cfmLimit;
2257 Value cfmMaximum;
2258 try
2259 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002260 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002261 cfmLimitSettingPath, cfmLimitIface,
2262 "Limit");
2263 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002264 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002265 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2266 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002267 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002268 {
2269 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002270 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002271 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002272 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002273 }
2274
James Feistacc8a4e2019-04-02 14:23:57 -07002275 double cfmMax = std::get<double>(cfmMaximum);
2276 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002277
James Feistacc8a4e2019-04-02 14:23:57 -07002278 cfmLim = std::floor(cfmLim + 0.5);
2279 cfmMax = std::floor(cfmMax + 0.5);
2280 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2281 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002282
James Feistacc8a4e2019-04-02 14:23:57 -07002283 return ipmi::responseSuccess(
2284 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002285 }
James Feistacc8a4e2019-04-02 14:23:57 -07002286
James Feist5f957ca2019-03-14 15:33:55 -07002287 else
2288 {
2289 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002290 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002291 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002292 }
2293}
2294
Jason M. Bills0748c692022-09-08 15:34:08 -07002295using crConfigVariant = ipmi::DbusVariant;
Cheng C Yang773703a2019-08-15 09:41:11 +08002296
Vernon Mauerydcff1502022-09-28 11:12:46 -07002297int setCRConfig(ipmi::Context::ptr& ctx, const std::string& property,
Cheng C Yang773703a2019-08-15 09:41:11 +08002298 const crConfigVariant& value,
Vernon Mauerydcff1502022-09-28 11:12:46 -07002299 [[maybe_unused]] std::chrono::microseconds timeout =
2300 ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002301{
2302 boost::system::error_code ec;
2303 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002304 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002305 "/xyz/openbmc_project/control/power_supply_redundancy",
2306 "org.freedesktop.DBus.Properties", "Set",
2307 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2308 if (ec)
2309 {
2310 phosphor::logging::log<phosphor::logging::level::ERR>(
2311 "Failed to set dbus property to cold redundancy");
2312 return -1;
2313 }
2314
2315 return 0;
2316}
2317
Kuiying Wange45333a2020-07-22 22:06:37 +08002318int getCRConfig(
Vernon Mauerydcff1502022-09-28 11:12:46 -07002319 ipmi::Context::ptr& ctx, const std::string& property,
2320 crConfigVariant& value,
Kuiying Wange45333a2020-07-22 22:06:37 +08002321 const std::string& service = "xyz.openbmc_project.PSURedundancy",
Vernon Mauerydcff1502022-09-28 11:12:46 -07002322 [[maybe_unused]] std::chrono::microseconds timeout =
2323 ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002324{
2325 boost::system::error_code ec;
2326 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002327 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002328 "/xyz/openbmc_project/control/power_supply_redundancy",
2329 "org.freedesktop.DBus.Properties", "Get",
2330 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2331 if (ec)
2332 {
2333 phosphor::logging::log<phosphor::logging::level::ERR>(
2334 "Failed to get dbus property to cold redundancy");
2335 return -1;
2336 }
2337 return 0;
2338}
2339
2340uint8_t getPSUCount(void)
2341{
2342 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2343 ipmi::Value num;
2344 try
2345 {
2346 num = ipmi::getDbusProperty(
2347 *dbus, "xyz.openbmc_project.PSURedundancy",
2348 "/xyz/openbmc_project/control/power_supply_redundancy",
2349 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2350 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002351 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002352 {
2353 phosphor::logging::log<phosphor::logging::level::ERR>(
2354 "Failed to get PSUNumber property from dbus interface");
2355 return 0;
2356 }
2357 uint8_t* pNum = std::get_if<uint8_t>(&num);
2358 if (!pNum)
2359 {
2360 phosphor::logging::log<phosphor::logging::level::ERR>(
2361 "Error to get PSU Number");
2362 return 0;
2363 }
2364 return *pNum;
2365}
2366
2367bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2368{
2369 if (conf.size() < num)
2370 {
2371 phosphor::logging::log<phosphor::logging::level::ERR>(
2372 "Invalid PSU Ranking");
2373 return false;
2374 }
2375 std::set<uint8_t> confSet;
2376 for (uint8_t i = 0; i < num; i++)
2377 {
2378 if (conf[i] > num)
2379 {
2380 phosphor::logging::log<phosphor::logging::level::ERR>(
2381 "PSU Ranking is larger than current PSU number");
2382 return false;
2383 }
2384 confSet.emplace(conf[i]);
2385 }
2386
2387 if (confSet.size() != num)
2388 {
2389 phosphor::logging::log<phosphor::logging::level::ERR>(
2390 "duplicate PSU Ranking");
2391 return false;
2392 }
2393 return true;
2394}
2395
2396enum class crParameter
2397{
2398 crStatus = 0,
2399 crFeature = 1,
2400 rotationFeature = 2,
2401 rotationAlgo = 3,
2402 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002403 numOfPSU = 5,
2404 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002405};
2406
2407constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2408static const constexpr uint32_t oneDay = 0x15180;
2409static const constexpr uint32_t oneMonth = 0xf53700;
2410static const constexpr uint8_t userSpecific = 0x01;
2411static const constexpr uint8_t crSetCompleted = 0;
Patrick Williams1bcced02024-08-16 15:20:24 -04002412ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(
2413 ipmi::Context::ptr& ctx, uint8_t parameter, ipmi::message::Payload& payload)
Cheng C Yang773703a2019-08-15 09:41:11 +08002414{
2415 switch (static_cast<crParameter>(parameter))
2416 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002417 case crParameter::rotationFeature:
2418 {
2419 uint8_t param1;
2420 if (payload.unpack(param1) || !payload.fullyUnpacked())
2421 {
2422 return ipmi::responseReqDataLenInvalid();
2423 }
2424 // Rotation Enable can only be true or false
2425 if (param1 > 1)
2426 {
2427 return ipmi::responseInvalidFieldRequest();
2428 }
2429 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2430 {
2431 return ipmi::responseResponseError();
2432 }
2433 break;
2434 }
2435 case crParameter::rotationAlgo:
2436 {
2437 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2438 std::string algoName;
2439 uint8_t param1;
2440 if (payload.unpack(param1))
2441 {
2442 return ipmi::responseReqDataLenInvalid();
2443 }
2444 switch (param1)
2445 {
2446 case 0:
2447 algoName = "xyz.openbmc_project.Control."
2448 "PowerSupplyRedundancy.Algo.bmcSpecific";
2449 break;
2450 case 1:
2451 algoName = "xyz.openbmc_project.Control."
2452 "PowerSupplyRedundancy.Algo.userSpecific";
2453 break;
2454 default:
2455 return ipmi::responseInvalidFieldRequest();
2456 }
2457 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2458 {
2459 return ipmi::responseResponseError();
2460 }
2461
2462 uint8_t numberOfPSU = getPSUCount();
2463 if (!numberOfPSU)
2464 {
2465 return ipmi::responseResponseError();
2466 }
2467 std::vector<uint8_t> rankOrder;
2468
2469 if (param1 == userSpecific)
2470 {
2471 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2472 {
2473 ipmi::responseReqDataLenInvalid();
2474 }
Yong Li83315132019-10-23 17:42:24 +08002475 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002476 {
2477 return ipmi::responseReqDataLenInvalid();
2478 }
2479
2480 if (!validateCRAlgo(rankOrder, numberOfPSU))
2481 {
2482 return ipmi::responseInvalidFieldRequest();
2483 }
2484 }
2485 else
2486 {
2487 if (rankOrder.size() > 0)
2488 {
2489 return ipmi::responseReqDataLenInvalid();
2490 }
2491 for (uint8_t i = 1; i <= numberOfPSU; i++)
2492 {
2493 rankOrder.emplace_back(i);
2494 }
2495 }
2496 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2497 {
2498 return ipmi::responseResponseError();
2499 }
2500 break;
2501 }
2502 case crParameter::rotationPeriod:
2503 {
2504 // Minimum Rotation period is One day (86400 seconds) and Max
2505 // Rotation Period is 6 month (0xf53700 seconds)
2506 uint32_t period;
2507 if (payload.unpack(period) || !payload.fullyUnpacked())
2508 {
2509 return ipmi::responseReqDataLenInvalid();
2510 }
2511 if ((period < oneDay) || (period > oneMonth))
2512 {
2513 return ipmi::responseInvalidFieldRequest();
2514 }
2515 if (setCRConfig(ctx, "PeriodOfRotation", period))
2516 {
2517 return ipmi::responseResponseError();
2518 }
2519 break;
2520 }
2521 default:
2522 {
2523 return ipmi::response(ccParameterNotSupported);
2524 }
2525 }
2526
Cheng C Yang773703a2019-08-15 09:41:11 +08002527 return ipmi::responseSuccess(crSetCompleted);
2528}
2529
Yong Li83315132019-10-23 17:42:24 +08002530ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Vernon Mauerydcff1502022-09-28 11:12:46 -07002531 ipmiOEMGetCRConfig(ipmi::Context::ptr& ctx, uint8_t parameter)
Cheng C Yang773703a2019-08-15 09:41:11 +08002532{
2533 crConfigVariant value;
2534 switch (static_cast<crParameter>(parameter))
2535 {
2536 case crParameter::crStatus:
2537 {
2538 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2539 {
2540 return ipmi::responseResponseError();
2541 }
2542 std::string* pStatus = std::get_if<std::string>(&value);
2543 if (!pStatus)
2544 {
2545 phosphor::logging::log<phosphor::logging::level::ERR>(
2546 "Error to get ColdRedundancyStatus property");
2547 return ipmi::responseResponseError();
2548 }
2549 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2550 auto status =
2551 server::PowerSupplyRedundancy::convertStatusFromString(
2552 *pStatus);
2553 switch (status)
2554 {
2555 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002556 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002557 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002558
2559 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002560 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002561 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002562 default:
2563 phosphor::logging::log<phosphor::logging::level::ERR>(
2564 "Error to get valid status");
2565 return ipmi::responseResponseError();
2566 }
2567 }
2568 case crParameter::crFeature:
2569 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002570 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002571 {
2572 return ipmi::responseResponseError();
2573 }
2574 bool* pResponse = std::get_if<bool>(&value);
2575 if (!pResponse)
2576 {
2577 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002578 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002579 return ipmi::responseResponseError();
2580 }
2581
Cheng C Yangf41e3342019-09-10 04:47:23 +08002582 return ipmi::responseSuccess(parameter,
2583 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002584 }
2585 case crParameter::rotationFeature:
2586 {
2587 if (getCRConfig(ctx, "RotationEnabled", value))
2588 {
2589 return ipmi::responseResponseError();
2590 }
2591 bool* pResponse = std::get_if<bool>(&value);
2592 if (!pResponse)
2593 {
2594 phosphor::logging::log<phosphor::logging::level::ERR>(
2595 "Error to get RotationEnabled property");
2596 return ipmi::responseResponseError();
2597 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002598 return ipmi::responseSuccess(parameter,
2599 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002600 }
2601 case crParameter::rotationAlgo:
2602 {
2603 if (getCRConfig(ctx, "RotationAlgorithm", value))
2604 {
2605 return ipmi::responseResponseError();
2606 }
2607
2608 std::string* pAlgo = std::get_if<std::string>(&value);
2609 if (!pAlgo)
2610 {
2611 phosphor::logging::log<phosphor::logging::level::ERR>(
2612 "Error to get RotationAlgorithm property");
2613 return ipmi::responseResponseError();
2614 }
Yong Li83315132019-10-23 17:42:24 +08002615 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002616 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2617 auto algo =
2618 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002619
Cheng C Yang773703a2019-08-15 09:41:11 +08002620 switch (algo)
2621 {
2622 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002623 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002624 break;
2625 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002626 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002627 break;
2628 default:
2629 phosphor::logging::log<phosphor::logging::level::ERR>(
2630 "Error to get valid algo");
2631 return ipmi::responseResponseError();
2632 }
2633
2634 if (getCRConfig(ctx, "RotationRankOrder", value))
2635 {
2636 return ipmi::responseResponseError();
2637 }
2638 std::vector<uint8_t>* pResponse =
2639 std::get_if<std::vector<uint8_t>>(&value);
2640 if (!pResponse)
2641 {
2642 phosphor::logging::log<phosphor::logging::level::ERR>(
2643 "Error to get RotationRankOrder property");
2644 return ipmi::responseResponseError();
2645 }
Yong Li83315132019-10-23 17:42:24 +08002646
Cheng C Yang773703a2019-08-15 09:41:11 +08002647 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002648 std::back_inserter(response));
2649
Cheng C Yangf41e3342019-09-10 04:47:23 +08002650 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002651 }
2652 case crParameter::rotationPeriod:
2653 {
2654 if (getCRConfig(ctx, "PeriodOfRotation", value))
2655 {
2656 return ipmi::responseResponseError();
2657 }
2658 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2659 if (!pResponse)
2660 {
2661 phosphor::logging::log<phosphor::logging::level::ERR>(
2662 "Error to get RotationAlgorithm property");
2663 return ipmi::responseResponseError();
2664 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002665 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002666 }
2667 case crParameter::numOfPSU:
2668 {
2669 uint8_t numberOfPSU = getPSUCount();
2670 if (!numberOfPSU)
2671 {
2672 return ipmi::responseResponseError();
2673 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002674 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002675 }
Yong Li19445ab2019-12-20 18:25:29 +08002676 case crParameter::rotationRankOrderEffective:
2677 {
2678 if (getCRConfig(ctx, "RotationRankOrder", value,
2679 "xyz.openbmc_project.PSURedundancy"))
2680 {
2681 return ipmi::responseResponseError();
2682 }
2683 std::vector<uint8_t>* pResponse =
2684 std::get_if<std::vector<uint8_t>>(&value);
2685 if (!pResponse)
2686 {
2687 phosphor::logging::log<phosphor::logging::level::ERR>(
2688 "Error to get effective RotationRankOrder property");
2689 return ipmi::responseResponseError();
2690 }
2691 return ipmi::responseSuccess(parameter, *pResponse);
2692 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002693 default:
2694 {
2695 return ipmi::response(ccParameterNotSupported);
2696 }
2697 }
2698}
2699
Patrick Williams1bcced02024-08-16 15:20:24 -04002700ipmi::RspType<> ipmiOEMSetFaultIndication(
2701 uint8_t sourceId, uint8_t faultType, uint8_t faultState, uint8_t faultGroup,
2702 std::array<uint8_t, 8>& ledStateData)
Zhu, Yungebe560b02019-04-21 21:19:21 -04002703{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002704 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2705 static const std::array<std::string, maxFaultType> faultNames = {
2706 "faultFan", "faultTemp", "faultPower",
2707 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002708
2709 constexpr uint8_t maxFaultSource = 0x4;
2710 constexpr uint8_t skipLEDs = 0xFF;
2711 constexpr uint8_t pinSize = 64;
2712 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002713 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002714
Zhikui Rence4e73f2019-12-06 13:59:47 -08002715 // same pin names need to be defined in dts file
2716 static const std::array<std::array<std::string, groupSize>, groupNum>
2717 faultLedPinNames = {{
2718 "LED_CPU1_CH1_DIMM1_FAULT",
2719 "LED_CPU1_CH1_DIMM2_FAULT",
2720 "LED_CPU1_CH2_DIMM1_FAULT",
2721 "LED_CPU1_CH2_DIMM2_FAULT",
2722 "LED_CPU1_CH3_DIMM1_FAULT",
2723 "LED_CPU1_CH3_DIMM2_FAULT",
2724 "LED_CPU1_CH4_DIMM1_FAULT",
2725 "LED_CPU1_CH4_DIMM2_FAULT",
2726 "LED_CPU1_CH5_DIMM1_FAULT",
2727 "LED_CPU1_CH5_DIMM2_FAULT",
2728 "LED_CPU1_CH6_DIMM1_FAULT",
2729 "LED_CPU1_CH6_DIMM2_FAULT",
2730 "",
2731 "",
2732 "",
2733 "", // end of group1
2734 "LED_CPU2_CH1_DIMM1_FAULT",
2735 "LED_CPU2_CH1_DIMM2_FAULT",
2736 "LED_CPU2_CH2_DIMM1_FAULT",
2737 "LED_CPU2_CH2_DIMM2_FAULT",
2738 "LED_CPU2_CH3_DIMM1_FAULT",
2739 "LED_CPU2_CH3_DIMM2_FAULT",
2740 "LED_CPU2_CH4_DIMM1_FAULT",
2741 "LED_CPU2_CH4_DIMM2_FAULT",
2742 "LED_CPU2_CH5_DIMM1_FAULT",
2743 "LED_CPU2_CH5_DIMM2_FAULT",
2744 "LED_CPU2_CH6_DIMM1_FAULT",
2745 "LED_CPU2_CH6_DIMM2_FAULT",
2746 "",
2747 "",
2748 "",
2749 "", // endof group2
2750 "LED_CPU3_CH1_DIMM1_FAULT",
2751 "LED_CPU3_CH1_DIMM2_FAULT",
2752 "LED_CPU3_CH2_DIMM1_FAULT",
2753 "LED_CPU3_CH2_DIMM2_FAULT",
2754 "LED_CPU3_CH3_DIMM1_FAULT",
2755 "LED_CPU3_CH3_DIMM2_FAULT",
2756 "LED_CPU3_CH4_DIMM1_FAULT",
2757 "LED_CPU3_CH4_DIMM2_FAULT",
2758 "LED_CPU3_CH5_DIMM1_FAULT",
2759 "LED_CPU3_CH5_DIMM2_FAULT",
2760 "LED_CPU3_CH6_DIMM1_FAULT",
2761 "LED_CPU3_CH6_DIMM2_FAULT",
2762 "",
2763 "",
2764 "",
2765 "", // end of group3
2766 "LED_CPU4_CH1_DIMM1_FAULT",
2767 "LED_CPU4_CH1_DIMM2_FAULT",
2768 "LED_CPU4_CH2_DIMM1_FAULT",
2769 "LED_CPU4_CH2_DIMM2_FAULT",
2770 "LED_CPU4_CH3_DIMM1_FAULT",
2771 "LED_CPU4_CH3_DIMM2_FAULT",
2772 "LED_CPU4_CH4_DIMM1_FAULT",
2773 "LED_CPU4_CH4_DIMM2_FAULT",
2774 "LED_CPU4_CH5_DIMM1_FAULT",
2775 "LED_CPU4_CH5_DIMM2_FAULT",
2776 "LED_CPU4_CH6_DIMM1_FAULT",
2777 "LED_CPU4_CH6_DIMM2_FAULT",
2778 "",
2779 "",
2780 "",
2781 "", // end of group4
2782 "LED_FAN1_FAULT",
2783 "LED_FAN2_FAULT",
2784 "LED_FAN3_FAULT",
2785 "LED_FAN4_FAULT",
2786 "LED_FAN5_FAULT",
2787 "LED_FAN6_FAULT",
2788 "LED_FAN7_FAULT",
2789 "LED_FAN8_FAULT",
2790 "",
2791 "",
2792 "",
2793 "",
2794 "",
2795 "",
2796 "",
2797 "" // end of group5
2798 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002799
Zhikui Rence4e73f2019-12-06 13:59:47 -08002800 // Validate the source, fault type --
2801 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2802 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2803 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2804 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2805 // definition differs based on fault type (Byte 2)
2806 // Type Fan=> Group: 0=FanGroupID, FF-not used
2807 // Byte 5-11 00h, not used
2808 // Byte12 FanLedState [7:0]-Fans 7:0
2809 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2810 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2811 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2812 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2813 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2814 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2815 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2816 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002817 if ((sourceId >= maxFaultSource) ||
2818 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2819 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2820 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2821 {
2822 return ipmi::responseParmOutOfRange();
2823 }
2824
Zhikui Rence4e73f2019-12-06 13:59:47 -08002825 size_t pinGroupOffset = 0;
2826 size_t pinGroupMax = pinSize / groupSize;
2827 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002828 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002829 pinGroupOffset = 4;
2830 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002831 }
2832
2833 switch (RemoteFaultType(faultType))
2834 {
2835 case (RemoteFaultType::fan):
2836 case (RemoteFaultType::memory):
2837 {
2838 if (faultGroup == skipLEDs)
2839 {
2840 return ipmi::responseSuccess();
2841 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002842 // calculate led state bit filed count, each byte has 8bits
2843 // the maximum bits will be 8 * 8 bits
2844 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002845
2846 // assemble ledState
2847 uint64_t ledState = 0;
2848 bool hasError = false;
Vernon Mauerydcff1502022-09-28 11:12:46 -07002849 for (size_t i = 0; i < sizeof(ledStateData); i++)
Zhu, Yungebe560b02019-04-21 21:19:21 -04002850 {
2851 ledState = (uint64_t)(ledState << 8);
2852 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2853 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002854 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002855
Vernon Mauerydcff1502022-09-28 11:12:46 -07002856 for (size_t group = 0; group < pinGroupMax; group++)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002857 {
2858 for (int i = 0; i < groupSize; i++)
2859 { // skip non-existing pins
2860 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2861 {
2862 continue;
2863 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002864
Zhikui Rence4e73f2019-12-06 13:59:47 -08002865 gpiod::line line = gpiod::find_line(
2866 faultLedPinNames[group + pinGroupOffset][i]);
2867 if (!line)
2868 {
2869 phosphor::logging::log<phosphor::logging::level::ERR>(
2870 "Not Find Led Gpio Device!",
2871 phosphor::logging::entry(
2872 "DEVICE=%s",
2873 faultLedPinNames[group + pinGroupOffset][i]
2874 .c_str()));
2875 hasError = true;
2876 continue;
2877 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002878
Zhikui Rence4e73f2019-12-06 13:59:47 -08002879 bool activeHigh =
2880 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2881 try
2882 {
2883 line.request(
2884 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2885 activeHigh
2886 ? 0
2887 : gpiod::line_request::FLAG_ACTIVE_LOW});
2888 line.set_value(ledStateBits[i + group * groupSize]);
2889 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002890 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002891 {
2892 phosphor::logging::log<phosphor::logging::level::ERR>(
2893 "Error write Led Gpio Device!",
2894 phosphor::logging::entry(
2895 "DEVICE=%s",
2896 faultLedPinNames[group + pinGroupOffset][i]
2897 .c_str()));
2898 hasError = true;
2899 continue;
2900 }
2901 } // for int i
2902 }
2903 if (hasError)
2904 {
2905 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002906 }
2907 break;
2908 }
2909 default:
2910 {
2911 // now only support two fault types
2912 return ipmi::responseParmOutOfRange();
2913 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002914 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002915 return ipmi::responseSuccess();
2916}
2917
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302918ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2919{
2920 uint8_t prodId = 0;
2921 try
2922 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002923 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302924 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002925 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302926 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2927 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002928 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302929 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2930 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302931 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2932 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002933 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302934 {
2935 phosphor::logging::log<phosphor::logging::level::ERR>(
2936 "ipmiOEMReadBoardProductId: Product ID read failed!",
2937 phosphor::logging::entry("ERR=%s", e.what()));
2938 }
2939 return ipmi::responseSuccess(prodId);
2940}
2941
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302942/** @brief implements the get security mode command
2943 * @param ctx - ctx pointer
2944 *
2945 * @returns IPMI completion code with following data
2946 * - restriction mode value - As specified in
2947 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2948 * - special mode value - As specified in
2949 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2950 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07002951ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr& ctx)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302952{
2953 namespace securityNameSpace =
2954 sdbusplus::xyz::openbmc_project::Control::Security::server;
2955 uint8_t restrictionModeValue = 0;
2956 uint8_t specialModeValue = 0;
2957
2958 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07002959 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07002960 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302961 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2962 restricionModeProperty);
2963 if (ec)
2964 {
2965 phosphor::logging::log<phosphor::logging::level::ERR>(
2966 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2967 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2968 return ipmi::responseUnspecifiedError();
2969 }
2970 restrictionModeValue = static_cast<uint8_t>(
2971 securityNameSpace::RestrictionMode::convertModesFromString(
2972 std::get<std::string>(varRestrMode)));
Jason M. Bills0748c692022-09-08 15:34:08 -07002973 auto varSpecialMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
2974 ctx->yield, ec, specialModeService, specialModeBasePath,
2975 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2976 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302977 if (ec)
2978 {
2979 phosphor::logging::log<phosphor::logging::level::ERR>(
2980 "ipmiGetSecurityMode: failed to get SpecialMode property",
2981 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2982 // fall through, let us not worry about SpecialMode property, which is
2983 // not required in user scenario
2984 }
2985 else
2986 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302987 specialModeValue = static_cast<uint8_t>(
2988 securityNameSpace::SpecialMode::convertModesFromString(
2989 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302990 }
2991 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2992}
2993
2994/** @brief implements the set security mode command
2995 * Command allows to upgrade the restriction mode and won't allow
2996 * to downgrade from system interface
2997 * @param ctx - ctx pointer
2998 * @param restrictionMode - restriction mode value to be set.
2999 *
3000 * @returns IPMI completion code
3001 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07003002ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr& ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303003 uint8_t restrictionMode,
3004 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303005{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303006#ifndef BMC_VALIDATION_UNSECURE_FEATURE
3007 if (specialMode)
3008 {
3009 return ipmi::responseReqDataLenInvalid();
3010 }
3011#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303012 namespace securityNameSpace =
3013 sdbusplus::xyz::openbmc_project::Control::Security::server;
3014
3015 ChannelInfo chInfo;
3016 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
3017 {
3018 phosphor::logging::log<phosphor::logging::level::ERR>(
3019 "ipmiSetSecurityMode: Failed to get Channel Info",
3020 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
3021 return ipmi::responseUnspecifiedError();
3022 }
3023 auto reqMode =
3024 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
3025
3026 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
3027 (reqMode >
3028 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
3029 {
3030 return ipmi::responseInvalidFieldRequest();
3031 }
3032
3033 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07003034 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07003035 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303036 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
3037 restricionModeProperty);
3038 if (ec)
3039 {
3040 phosphor::logging::log<phosphor::logging::level::ERR>(
3041 "ipmiSetSecurityMode: failed to get RestrictionMode property",
3042 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3043 return ipmi::responseUnspecifiedError();
3044 }
3045 auto currentRestrictionMode =
3046 securityNameSpace::RestrictionMode::convertModesFromString(
3047 std::get<std::string>(varRestrMode));
3048
3049 if (chInfo.mediumType !=
3050 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
3051 currentRestrictionMode > reqMode)
3052 {
3053 phosphor::logging::log<phosphor::logging::level::ERR>(
3054 "ipmiSetSecurityMode - Downgrading security mode not supported "
3055 "through system interface",
3056 phosphor::logging::entry(
3057 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
3058 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
3059 return ipmi::responseCommandNotAvailable();
3060 }
3061
3062 ec.clear();
3063 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07003064 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303065 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
3066 restricionModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003067 static_cast<ipmi::DbusVariant>(
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303068 securityNameSpace::convertForMessage(reqMode)));
3069
3070 if (ec)
3071 {
3072 phosphor::logging::log<phosphor::logging::level::ERR>(
3073 "ipmiSetSecurityMode: failed to set RestrictionMode property",
3074 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3075 return ipmi::responseUnspecifiedError();
3076 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303077
3078#ifdef BMC_VALIDATION_UNSECURE_FEATURE
3079 if (specialMode)
3080 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00003081 constexpr uint8_t mfgMode = 0x01;
3082 // Manufacturing mode is reserved. So can't enable this mode.
3083 if (specialMode.value() == mfgMode)
3084 {
3085 phosphor::logging::log<phosphor::logging::level::INFO>(
3086 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
3087 return ipmi::responseInvalidFieldRequest();
3088 }
3089
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303090 ec.clear();
3091 ctx->bus->yield_method_call<>(
3092 ctx->yield, ec, specialModeService, specialModeBasePath,
3093 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
3094 specialModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003095 static_cast<ipmi::DbusVariant>(securityNameSpace::convertForMessage(
3096 static_cast<securityNameSpace::SpecialMode::Modes>(
3097 specialMode.value()))));
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303098
3099 if (ec)
3100 {
3101 phosphor::logging::log<phosphor::logging::level::ERR>(
3102 "ipmiSetSecurityMode: failed to set SpecialMode property",
3103 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3104 return ipmi::responseUnspecifiedError();
3105 }
3106 }
3107#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303108 return ipmi::responseSuccess();
3109}
3110
Jason M. Bills97d1fb32025-04-23 08:57:35 -07003111ipmi::RspType<uint8_t /* restore status */> ipmiRestoreConfiguration(
3112 const std::array<uint8_t, 3>& clr, uint8_t cmd)
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003113{
3114 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
3115
3116 if (clr != expClr)
3117 {
3118 return ipmi::responseInvalidFieldRequest();
3119 }
3120 constexpr uint8_t cmdStatus = 0;
3121 constexpr uint8_t cmdDefaultRestore = 0xaa;
3122 constexpr uint8_t cmdFullRestore = 0xbb;
3123 constexpr uint8_t cmdFormat = 0xcc;
3124
3125 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3126
3127 switch (cmd)
3128 {
3129 case cmdStatus:
3130 break;
3131 case cmdDefaultRestore:
3132 case cmdFullRestore:
3133 case cmdFormat:
3134 {
3135 // write file to rwfs root
3136 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3137 std::ofstream restoreFile(restoreOpFname);
3138 if (!restoreFile)
3139 {
3140 return ipmi::responseUnspecifiedError();
3141 }
3142 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303143
3144 phosphor::logging::log<phosphor::logging::level::WARNING>(
3145 "Restore to default will be performed on next BMC boot",
3146 phosphor::logging::entry("ACTION=0x%0X", cmd));
3147
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003148 break;
3149 }
3150 default:
3151 return ipmi::responseInvalidFieldRequest();
3152 }
3153
3154 constexpr uint8_t restorePending = 0;
3155 constexpr uint8_t restoreComplete = 1;
3156
3157 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3158 ? restorePending
3159 : restoreComplete;
3160 return ipmi::responseSuccess(restoreStatus);
3161}
3162
Chen Yugang39736d52019-07-12 16:24:33 +08003163ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3164{
3165 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003166 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003167
3168 try
3169 {
3170 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04003171 std::string service =
3172 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
3173 Value variant =
3174 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3175 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
Chen Yugang39736d52019-07-12 16:24:33 +08003176
3177 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3178 std::get<std::string>(variant)))
3179 {
3180 case nmi::NMISource::BMCSourceSignal::None:
3181 bmcSource = static_cast<uint8_t>(NmiSource::none);
3182 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003183 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3184 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003185 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003186 case nmi::NMISource::BMCSourceSignal::Watchdog:
3187 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003188 break;
3189 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3190 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3191 break;
3192 case nmi::NMISource::BMCSourceSignal::MemoryError:
3193 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3194 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003195 case nmi::NMISource::BMCSourceSignal::PciBusError:
3196 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003197 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003198 case nmi::NMISource::BMCSourceSignal::PCH:
3199 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003200 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003201 case nmi::NMISource::BMCSourceSignal::Chipset:
3202 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003203 break;
3204 default:
3205 phosphor::logging::log<phosphor::logging::level::ERR>(
3206 "NMI source: invalid property!",
3207 phosphor::logging::entry(
3208 "PROP=%s", std::get<std::string>(variant).c_str()));
3209 return ipmi::responseResponseError();
3210 }
3211 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05003212 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003213 {
3214 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3215 return ipmi::responseResponseError();
3216 }
3217
3218 return ipmi::responseSuccess(bmcSource);
3219}
3220
3221ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3222{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003223 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003224
3225 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3226 nmi::NMISource::BMCSourceSignal::None;
3227
3228 switch (NmiSource(sourceId))
3229 {
3230 case NmiSource::none:
3231 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3232 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003233 case NmiSource::frontPanelButton:
3234 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003235 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003236 case NmiSource::watchdog:
3237 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003238 break;
3239 case NmiSource::chassisCmd:
3240 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3241 break;
3242 case NmiSource::memoryError:
3243 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3244 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003245 case NmiSource::pciBusError:
3246 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003247 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003248 case NmiSource::pch:
3249 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003250 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003251 case NmiSource::chipset:
3252 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003253 break;
3254 default:
3255 phosphor::logging::log<phosphor::logging::level::ERR>(
3256 "NMI source: invalid property!");
3257 return ipmi::responseResponseError();
3258 }
3259
3260 try
3261 {
3262 // keep NMI signal source
3263 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04003264 std::string service =
3265 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003266 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3267 oemNmiBmcSourceObjPathProp,
3268 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003269 // set Enabled property to inform NMI source handling
3270 // to trigger a NMI_OUT BSOD.
3271 // if it's triggered by NMI source property changed,
3272 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3273 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3274 {
3275 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3276 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3277 static_cast<bool>(true));
3278 }
Chen Yugang39736d52019-07-12 16:24:33 +08003279 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003280 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003281 {
3282 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3283 return ipmi::responseResponseError();
3284 }
3285
3286 return ipmi::responseSuccess();
3287}
3288
James Feist63efafa2019-07-24 12:39:21 -07003289namespace dimmOffset
3290{
3291constexpr const char* dimmPower = "DimmPower";
3292constexpr const char* staticCltt = "StaticCltt";
3293constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3294constexpr const char* offsetInterface =
3295 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3296constexpr const char* property = "DimmOffset";
3297
3298}; // namespace dimmOffset
3299
Patrick Williams1bcced02024-08-16 15:20:24 -04003300ipmi::RspType<> ipmiOEMSetDimmOffset(
3301 uint8_t type, const std::vector<std::tuple<uint8_t, uint8_t>>& data)
James Feist63efafa2019-07-24 12:39:21 -07003302{
3303 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3304 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3305 {
3306 return ipmi::responseInvalidFieldRequest();
3307 }
3308
3309 if (data.empty())
3310 {
3311 return ipmi::responseInvalidFieldRequest();
3312 }
3313 nlohmann::json json;
3314
3315 std::ifstream jsonStream(dimmOffsetFile);
3316 if (jsonStream.good())
3317 {
3318 json = nlohmann::json::parse(jsonStream, nullptr, false);
3319 if (json.is_discarded())
3320 {
3321 json = nlohmann::json();
3322 }
3323 jsonStream.close();
3324 }
3325
3326 std::string typeName;
3327 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3328 {
3329 typeName = dimmOffset::dimmPower;
3330 }
3331 else
3332 {
3333 typeName = dimmOffset::staticCltt;
3334 }
3335
3336 nlohmann::json& field = json[typeName];
3337
3338 for (const auto& [index, value] : data)
3339 {
3340 field[index] = value;
3341 }
3342
3343 for (nlohmann::json& val : field)
3344 {
3345 if (val == nullptr)
3346 {
3347 val = static_cast<uint8_t>(0);
3348 }
3349 }
3350
3351 std::ofstream output(dimmOffsetFile);
3352 if (!output.good())
3353 {
3354 std::cerr << "Error writing json file\n";
3355 return ipmi::responseResponseError();
3356 }
3357
3358 output << json.dump(4);
3359
3360 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3361 {
3362 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3363
Jason M. Bills0748c692022-09-08 15:34:08 -07003364 ipmi::DbusVariant offsets = field.get<std::vector<uint8_t>>();
James Feist63efafa2019-07-24 12:39:21 -07003365 auto call = bus->new_method_call(
3366 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3367 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3368 try
3369 {
3370 bus->call(call);
3371 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003372 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003373 {
3374 phosphor::logging::log<phosphor::logging::level::ERR>(
3375 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3376 phosphor::logging::entry("ERR=%s", e.what()));
3377 return ipmi::responseResponseError();
3378 }
3379 }
3380
3381 return ipmi::responseSuccess();
3382}
3383
3384ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3385{
James Feist63efafa2019-07-24 12:39:21 -07003386 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3387 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3388 {
3389 return ipmi::responseInvalidFieldRequest();
3390 }
3391
3392 std::ifstream jsonStream(dimmOffsetFile);
3393
3394 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3395 if (json.is_discarded())
3396 {
3397 std::cerr << "File error in " << dimmOffsetFile << "\n";
3398 return ipmi::responseResponseError();
3399 }
3400
3401 std::string typeName;
3402 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3403 {
3404 typeName = dimmOffset::dimmPower;
3405 }
3406 else
3407 {
3408 typeName = dimmOffset::staticCltt;
3409 }
3410
3411 auto it = json.find(typeName);
3412 if (it == json.end())
3413 {
3414 return ipmi::responseInvalidFieldRequest();
3415 }
3416
3417 if (it->size() <= index)
3418 {
3419 return ipmi::responseInvalidFieldRequest();
3420 }
3421
3422 uint8_t resp = it->at(index).get<uint8_t>();
3423 return ipmi::responseSuccess(resp);
3424}
3425
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003426namespace boot_options
3427{
3428
3429using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3430using IpmiValue = uint8_t;
3431constexpr auto ipmiDefault = 0;
3432
3433std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3434 {0x01, Source::Sources::Network},
3435 {0x02, Source::Sources::Disk},
3436 {0x05, Source::Sources::ExternalMedia},
3437 {0x0f, Source::Sources::RemovableMedia},
3438 {ipmiDefault, Source::Sources::Default}};
3439
3440std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003441 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003442
3443std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3444 {Source::Sources::Network, 0x01},
3445 {Source::Sources::Disk, 0x02},
3446 {Source::Sources::ExternalMedia, 0x05},
3447 {Source::Sources::RemovableMedia, 0x0f},
3448 {Source::Sources::Default, ipmiDefault}};
3449
3450std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003451 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003452
3453static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3454static constexpr auto bootSourceIntf =
3455 "xyz.openbmc_project.Control.Boot.Source";
3456static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3457static constexpr auto persistentObjPath =
3458 "/xyz/openbmc_project/control/host0/boot";
3459static constexpr auto oneTimePath =
3460 "/xyz/openbmc_project/control/host0/boot/one_time";
3461static constexpr auto bootSourceProp = "BootSource";
3462static constexpr auto bootModeProp = "BootMode";
3463static constexpr auto oneTimeBootEnableProp = "Enabled";
3464static constexpr auto httpBootMode =
3465 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3466
3467enum class BootOptionParameter : size_t
3468{
3469 setInProgress = 0x0,
3470 bootFlags = 0x5,
3471};
3472static constexpr uint8_t setComplete = 0x0;
3473static constexpr uint8_t setInProgress = 0x1;
3474static uint8_t transferStatus = setComplete;
3475static constexpr uint8_t setParmVersion = 0x01;
3476static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3477static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3478static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3479static constexpr uint8_t httpBoot = 0xd;
3480static constexpr uint8_t bootSourceMask = 0x3c;
3481
3482} // namespace boot_options
3483
3484ipmi::RspType<uint8_t, // version
3485 uint8_t, // param
3486 uint8_t, // data0, dependent on parameter
3487 std::optional<uint8_t> // data1, dependent on parameter
3488 >
Vernon Mauerydcff1502022-09-28 11:12:46 -07003489 ipmiOemGetEfiBootOptions(uint8_t parameter, [[maybe_unused]] uint8_t set,
3490 [[maybe_unused]] uint8_t block)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003491{
3492 using namespace boot_options;
3493 uint8_t bootOption = 0;
3494
3495 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3496 {
3497 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3498 std::nullopt);
3499 }
3500
3501 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3502 {
3503 phosphor::logging::log<phosphor::logging::level::ERR>(
3504 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003505 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003506 }
3507
3508 try
3509 {
3510 auto oneTimeEnabled = false;
3511 // read one time Enabled property
3512 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3513 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3514 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3515 enabledIntf, oneTimeBootEnableProp);
3516 oneTimeEnabled = std::get<bool>(variant);
3517
3518 // get BootSource and BootMode properties
3519 // according to oneTimeEnable
3520 auto bootObjPath = oneTimePath;
3521 if (oneTimeEnabled == false)
3522 {
3523 bootObjPath = persistentObjPath;
3524 }
3525
3526 service = getService(*dbus, bootModeIntf, bootObjPath);
3527 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3528 bootModeProp);
3529
3530 auto bootMode =
3531 Mode::convertModesFromString(std::get<std::string>(variant));
3532
3533 service = getService(*dbus, bootSourceIntf, bootObjPath);
3534 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3535 bootSourceProp);
3536
3537 if (std::get<std::string>(variant) == httpBootMode)
3538 {
3539 bootOption = httpBoot;
3540 }
3541 else
3542 {
3543 auto bootSource = Source::convertSourcesFromString(
3544 std::get<std::string>(variant));
3545 bootOption = sourceDbusToIpmi.at(bootSource);
3546 if (Source::Sources::Default == bootSource)
3547 {
3548 bootOption = modeDbusToIpmi.at(bootMode);
3549 }
3550 }
3551
3552 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3553 : setParmBootFlagsValidPermanent;
3554 bootOption <<= 2; // shift for responseconstexpr
3555 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3556 bootOption);
3557 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003558 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003559 {
3560 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3561 return ipmi::responseResponseError();
3562 }
3563}
3564
3565ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3566 std::optional<uint8_t> bootOption)
3567{
3568 using namespace boot_options;
3569 auto oneTimeEnabled = false;
3570
Mike Jonesbc01d212022-06-16 12:41:33 -07003571 if (bootFlag == 0 && bootParam == 0)
3572 {
3573 phosphor::logging::log<phosphor::logging::level::ERR>(
3574 "Unsupported parameter");
3575 return ipmi::response(ccParameterNotSupported);
3576 }
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003577 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3578 {
3579 if (bootOption)
3580 {
3581 return ipmi::responseReqDataLenInvalid();
3582 }
3583
3584 if (transferStatus == setInProgress)
3585 {
3586 phosphor::logging::log<phosphor::logging::level::ERR>(
3587 "boot option set in progress!");
3588 return ipmi::responseResponseError();
3589 }
3590
3591 transferStatus = bootParam;
3592 return ipmi::responseSuccess();
3593 }
3594
3595 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3596 {
3597 phosphor::logging::log<phosphor::logging::level::ERR>(
3598 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003599 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003600 }
3601
3602 if (!bootOption)
3603 {
3604 return ipmi::responseReqDataLenInvalid();
3605 }
3606
3607 if (((bootOption.value() & bootSourceMask) >> 2) !=
3608 httpBoot) // not http boot, exit
3609 {
3610 phosphor::logging::log<phosphor::logging::level::ERR>(
3611 "wrong boot option parameter!");
3612 return ipmi::responseParmOutOfRange();
3613 }
3614
3615 try
3616 {
3617 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3618 setParmBootFlagsPermanent;
3619
3620 // read one time Enabled property
3621 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3622 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3623 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3624 enabledIntf, oneTimeBootEnableProp);
3625 oneTimeEnabled = std::get<bool>(variant);
3626
3627 /*
3628 * Check if the current boot setting is onetime or permanent, if the
3629 * request in the command is otherwise, then set the "Enabled"
3630 * property in one_time object path to 'True' to indicate onetime
3631 * and 'False' to indicate permanent.
3632 *
3633 * Once the onetime/permanent setting is applied, then the bootMode
3634 * and bootSource is updated for the corresponding object.
3635 */
3636 if (permanent == oneTimeEnabled)
3637 {
3638 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3639 oneTimeBootEnableProp, !permanent);
3640 }
3641
3642 // set BootSource and BootMode properties
3643 // according to oneTimeEnable or persistent
3644 auto bootObjPath = oneTimePath;
3645 if (oneTimeEnabled == false)
3646 {
3647 bootObjPath = persistentObjPath;
3648 }
3649 std::string bootMode =
3650 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3651 std::string bootSource = httpBootMode;
3652
3653 service = getService(*dbus, bootModeIntf, bootObjPath);
3654 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3655 bootMode);
3656
3657 service = getService(*dbus, bootSourceIntf, bootObjPath);
3658 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3659 bootSourceProp, bootSource);
3660 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003661 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003662 {
3663 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3664 return ipmi::responseResponseError();
3665 }
3666
3667 return ipmi::responseSuccess();
3668}
3669
Jason M. Bills0748c692022-09-08 15:34:08 -07003670using BasicVariantType = ipmi::DbusVariant;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003671using PropertyMapType =
3672 boost::container::flat_map<std::string, BasicVariantType>;
3673static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3674 "xyz.openbmc_project.Configuration.PSUPresence"};
Vernon Mauerydcff1502022-09-28 11:12:46 -07003675int getPSUAddress(ipmi::Context::ptr& ctx, uint8_t& bus,
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003676 std::vector<uint64_t>& addrTable)
3677{
3678 boost::system::error_code ec;
3679 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3680 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3681 "/xyz/openbmc_project/object_mapper",
3682 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3683 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3684 if (ec)
3685 {
3686 phosphor::logging::log<phosphor::logging::level::ERR>(
3687 "Failed to set dbus property to cold redundancy");
3688 return -1;
3689 }
3690 for (const auto& object : subtree)
3691 {
3692 std::string pathName = object.first;
3693 for (const auto& serviceIface : object.second)
3694 {
3695 std::string serviceName = serviceIface.first;
3696
3697 ec.clear();
3698 PropertyMapType propMap =
3699 ctx->bus->yield_method_call<PropertyMapType>(
3700 ctx->yield, ec, serviceName, pathName,
3701 "org.freedesktop.DBus.Properties", "GetAll",
3702 "xyz.openbmc_project.Configuration.PSUPresence");
3703 if (ec)
3704 {
3705 phosphor::logging::log<phosphor::logging::level::ERR>(
3706 "Failed to set dbus property to cold redundancy");
3707 return -1;
3708 }
3709 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3710 auto psuAddress =
3711 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3712
3713 if (psuBus == nullptr || psuAddress == nullptr)
3714 {
3715 std::cerr << "error finding necessary "
3716 "entry in configuration\n";
3717 return -1;
3718 }
3719 bus = static_cast<uint8_t>(*psuBus);
3720 addrTable = *psuAddress;
3721 return 0;
3722 }
3723 }
3724 return -1;
3725}
3726
3727static const constexpr uint8_t addrOffset = 8;
3728static const constexpr uint8_t psuRevision = 0xd9;
3729static const constexpr uint8_t defaultPSUBus = 7;
3730// Second Minor, Primary Minor, Major
3731static const constexpr size_t verLen = 3;
Jason M. Bills97d1fb32025-04-23 08:57:35 -07003732ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(
3733 ipmi::Context::ptr& ctx)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003734{
3735 uint8_t bus = defaultPSUBus;
3736 std::vector<uint64_t> addrTable;
3737 std::vector<uint8_t> result;
3738 if (getPSUAddress(ctx, bus, addrTable))
3739 {
3740 std::cerr << "Failed to get PSU bus and address\n";
3741 return ipmi::responseResponseError();
3742 }
3743
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003744 for (const auto& targetAddr : addrTable)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003745 {
3746 std::vector<uint8_t> writeData = {psuRevision};
3747 std::vector<uint8_t> readBuf(verLen);
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003748 uint8_t addr = static_cast<uint8_t>(targetAddr) + addrOffset;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003749 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3750
3751 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3752 if (retI2C != ipmi::ccSuccess)
3753 {
3754 for (size_t idx = 0; idx < verLen; idx++)
3755 {
3756 result.emplace_back(0x00);
3757 }
3758 }
3759 else
3760 {
3761 for (const uint8_t& data : readBuf)
3762 {
3763 result.emplace_back(data);
3764 }
3765 }
3766 }
3767
3768 return ipmi::responseSuccess(result);
3769}
3770
Jason M. Bills97d1fb32025-04-23 08:57:35 -07003771std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr& ctx,
3772 const std::string& name)
srikanta mondal2030d7c2020-05-03 17:25:25 +00003773{
3774 Value dbusValue = 0;
3775 std::string serviceName;
3776
3777 boost::system::error_code ec =
3778 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3779
3780 if (ec)
3781 {
3782 phosphor::logging::log<phosphor::logging::level::ERR>(
3783 "Failed to perform Multinode getService.");
3784 return std::nullopt;
3785 }
3786
3787 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3788 multiNodeIntf, name, dbusValue);
3789 if (ec)
3790 {
3791 phosphor::logging::log<phosphor::logging::level::ERR>(
3792 "Failed to perform Multinode get property");
3793 return std::nullopt;
3794 }
3795
3796 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3797 if (!multiNodeVal)
3798 {
3799 phosphor::logging::log<phosphor::logging::level::ERR>(
3800 "getMultiNodeInfoPresence: error to get multinode");
3801 return std::nullopt;
3802 }
3803 return *multiNodeVal;
3804}
3805
3806/** @brief implements OEM get reading command
3807 * @param domain ID
3808 * @param reading Type
3809 * - 00h = platform Power Consumption
3810 * - 01h = inlet Air Temp
3811 * - 02h = icc_TDC from PECI
3812 * @param reserved, write as 0000h
3813 *
3814 * @returns IPMI completion code plus response data
3815 * - response
3816 * - domain ID
3817 * - reading Type
3818 * - 00h = platform Power Consumption
3819 * - 01h = inlet Air Temp
3820 * - 02h = icc_TDC from PECI
3821 * - reading
3822 */
3823ipmi::RspType<uint4_t, // domain ID
3824 uint4_t, // reading Type
3825 uint16_t // reading Value
3826 >
Vernon Mauerydcff1502022-09-28 11:12:46 -07003827 ipmiOEMGetReading(ipmi::Context::ptr& ctx, uint4_t domainId,
srikanta mondal2030d7c2020-05-03 17:25:25 +00003828 uint4_t readingType, uint16_t reserved)
3829{
Vernon Mauerydcff1502022-09-28 11:12:46 -07003830 [[maybe_unused]] constexpr uint8_t platformPower = 0;
srikanta mondal2030d7c2020-05-03 17:25:25 +00003831 constexpr uint8_t inletAirTemp = 1;
3832 constexpr uint8_t iccTdc = 2;
3833
3834 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3835 {
3836 return ipmi::responseInvalidFieldRequest();
3837 }
3838
3839 // This command should run only from multi-node product.
3840 // For all other platforms this command will return invalid.
3841
Patrick Williams1bcced02024-08-16 15:20:24 -04003842 std::optional<uint8_t> nodeInfo =
3843 getMultiNodeInfoPresence(ctx, "NodePresence");
srikanta mondal2030d7c2020-05-03 17:25:25 +00003844 if (!nodeInfo || !*nodeInfo)
3845 {
3846 return ipmi::responseInvalidCommand();
3847 }
3848
3849 uint16_t oemReadingValue = 0;
3850 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3851 {
3852 double value = 0;
3853 boost::system::error_code ec = ipmi::getDbusProperty(
3854 ctx, "xyz.openbmc_project.HwmonTempSensor",
3855 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3856 "xyz.openbmc_project.Sensor.Value", "Value", value);
3857 if (ec)
3858 {
3859 phosphor::logging::log<phosphor::logging::level::ERR>(
3860 "Failed to get BMC Get OEM temperature",
3861 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3862 return ipmi::responseUnspecifiedError();
3863 }
3864 // Take the Inlet temperature
3865 oemReadingValue = static_cast<uint16_t>(value);
3866 }
3867 else
3868 {
3869 phosphor::logging::log<phosphor::logging::level::ERR>(
3870 "Currently Get OEM Reading support only for Inlet Air Temp");
3871 return ipmi::responseParmOutOfRange();
3872 }
3873 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3874}
3875
AppaRao Puli28972062019-11-11 02:04:45 +05303876/** @brief implements the maximum size of
3877 * bridgeable messages used between KCS and
3878 * IPMB interfacesget security mode command.
3879 *
3880 * @returns IPMI completion code with following data
3881 * - KCS Buffer Size (In multiples of four bytes)
3882 * - IPMB Buffer Size (In multiples of four bytes)
3883 **/
3884ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3885{
3886 // for now this is hard coded; really this number is dependent on
3887 // the BMC kcs driver as well as the host kcs driver....
3888 // we can't know the latter.
3889 uint8_t kcsMaxBufferSize = 63 / 4;
3890 uint8_t ipmbMaxBufferSize = 128 / 4;
3891
3892 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3893}
3894
Jason M. Bills97d1fb32025-04-23 08:57:35 -07003895ipmi::RspType<std::vector<uint8_t>> ipmiOEMReadPFRMailbox(
3896 ipmi::Context::ptr& ctx, const uint8_t readRegister,
3897 const uint8_t numOfBytes, uint8_t registerIdentifier)
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003898{
3899 if (!ipmi::mailbox::i2cConfigLoaded)
3900 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003901 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003902 "Calling PFR Load Configuration Function to Get I2C Bus and Target "
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003903 "Address ");
3904
3905 ipmi::mailbox::loadPfrConfig(ctx, ipmi::mailbox::i2cConfigLoaded);
3906 }
3907
3908 if (!numOfBytes && !readRegister)
3909 {
3910 phosphor::logging::log<phosphor::logging::level::ERR>(
3911 "OEM IPMI command: Read & write count are 0 which is invalid ");
3912 return ipmi::responseInvalidFieldRequest();
3913 }
3914
3915 switch (registerIdentifier)
3916 {
3917 case ipmi::mailbox::registerType::fifoReadRegister:
3918 {
3919 // Check if readRegister is an FIFO read register
Vernon Mauerydcff1502022-09-28 11:12:46 -07003920 if (ipmi::mailbox::readFifoReg.find(readRegister) ==
3921 ipmi::mailbox::readFifoReg.end())
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003922 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003923 phosphor::logging::log<phosphor::logging::level::ERR>(
Vernon Mauerydcff1502022-09-28 11:12:46 -07003924 "OEM IPMI command: Register is not a Read FIFO ");
3925 return ipmi::responseInvalidFieldRequest();
3926 }
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003927
Vernon Mauerydcff1502022-09-28 11:12:46 -07003928 phosphor::logging::log<phosphor::logging::level::ERR>(
3929 "OEM IPMI command: Register is a Read FIFO ");
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003930
Vernon Mauerydcff1502022-09-28 11:12:46 -07003931 ipmi::mailbox::writefifo(ipmi::mailbox::provisioningCommand,
3932 readRegister);
3933 ipmi::mailbox::writefifo(ipmi::mailbox::triggerCommand,
3934 ipmi::mailbox::flushRead);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003935
Vernon Mauerydcff1502022-09-28 11:12:46 -07003936 std::vector<uint8_t> writeData = {ipmi::mailbox::readFifo};
3937 std::vector<uint8_t> readBuf(1);
3938 std::vector<uint8_t> result;
3939
3940 for (int i = 0; i < numOfBytes; i++)
3941 {
3942 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
3943 ipmi::mailbox::targetAddr,
3944 writeData, readBuf);
3945 if (ret != ipmi::ccSuccess)
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003946 {
Vernon Mauerydcff1502022-09-28 11:12:46 -07003947 return ipmi::response(ret);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003948 }
3949
Vernon Mauerydcff1502022-09-28 11:12:46 -07003950 else
3951 {
3952 for (const uint8_t& data : readBuf)
3953 {
3954 result.emplace_back(data);
3955 }
3956 }
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003957 }
Vernon Mauerydcff1502022-09-28 11:12:46 -07003958
3959 return ipmi::responseSuccess(result);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003960 }
3961
3962 case ipmi::mailbox::registerType::singleByteRegister:
3963 {
3964 phosphor::logging::log<phosphor::logging::level::ERR>(
3965 "OEM IPMI command: Register is a Single Byte Register ");
3966
3967 std::vector<uint8_t> writeData = {readRegister};
3968 std::vector<uint8_t> readBuf(numOfBytes);
3969
3970 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003971 ipmi::mailbox::targetAddr,
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003972 writeData, readBuf);
3973 if (ret != ipmi::ccSuccess)
3974 {
3975 return ipmi::response(ret);
3976 }
3977 return ipmi::responseSuccess(readBuf);
3978 }
3979
3980 default:
3981 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003982 phosphor::logging::log<phosphor::logging::level::ERR>(
3983 "OEM IPMI command: Register identifier is not valid.It should "
3984 "be 0 "
3985 "for Single Byte Register and 1 for FIFO Read Register");
3986
3987 return ipmi::responseInvalidFieldRequest();
3988 }
3989 }
3990}
3991
Jason M. Bills64796042018-10-03 16:51:55 -07003992static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003993{
3994 phosphor::logging::log<phosphor::logging::level::INFO>(
3995 "Registering OEM commands");
Vernon Maueryaf652682023-08-04 13:37:21 -07003996 registerHandler(prioOemBase, intel::netFnGeneral,
3997 intel::general::cmdGetBmcVersionString, Privilege::User,
3998 ipmiOEMGetBmcVersionString);
3999
Vernon Mauery98bbf692019-09-16 11:14:59 -07004000 ipmiPrintAndRegister(intel::netFnGeneral,
4001 intel::general::cmdGetChassisIdentifier, NULL,
4002 ipmiOEMGetChassisIdentifier,
4003 PRIVILEGE_USER); // get chassis identifier
4004
4005 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
4006 NULL, ipmiOEMSetSystemGUID,
4007 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07004008
4009 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004010 registerHandler(prioOemBase, intel::netFnGeneral,
4011 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
4012 ipmiOEMDisableBMCSystemReset);
4013
Jason M. Billsb02bf092019-08-15 13:01:56 -07004014 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004015 registerHandler(prioOemBase, intel::netFnGeneral,
4016 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
4017 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07004018
Vernon Mauery98bbf692019-09-16 11:14:59 -07004019 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
4020 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004021
Chen Yugang7a04f3a2019-10-08 11:12:35 +08004022 registerHandler(prioOemBase, intel::netFnGeneral,
4023 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
4024 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004025
Vernon Mauery98bbf692019-09-16 11:14:59 -07004026 ipmiPrintAndRegister(intel::netFnGeneral,
4027 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
4028 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304029
Vernon Mauery98bbf692019-09-16 11:14:59 -07004030 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4031 intel::general::cmdSendEmbeddedFWUpdStatus,
4032 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304033
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05304034 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
4035 Privilege::Admin, ipmiOEMSlotIpmb);
4036
Vernon Mauery98bbf692019-09-16 11:14:59 -07004037 ipmiPrintAndRegister(intel::netFnGeneral,
4038 intel::general::cmdSetPowerRestoreDelay, NULL,
4039 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
4040
4041 ipmiPrintAndRegister(intel::netFnGeneral,
4042 intel::general::cmdGetPowerRestoreDelay, NULL,
4043 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
4044
4045 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4046 intel::general::cmdSetOEMUser2Activation,
4047 Privilege::Callback, ipmiOEMSetUser2Activation);
4048
4049 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4050 intel::general::cmdSetSpecialUserPassword,
4051 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05304052
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004053 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004054 registerHandler(prioOemBase, intel::netFnGeneral,
4055 intel::general::cmdGetProcessorErrConfig, Privilege::User,
4056 ipmiOEMGetProcessorErrConfig);
4057
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004058 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004059 registerHandler(prioOemBase, intel::netFnGeneral,
4060 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
4061 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004062
Vernon Mauery98bbf692019-09-16 11:14:59 -07004063 ipmiPrintAndRegister(intel::netFnGeneral,
4064 intel::general::cmdSetShutdownPolicy, NULL,
4065 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004066
Vernon Mauery98bbf692019-09-16 11:14:59 -07004067 ipmiPrintAndRegister(intel::netFnGeneral,
4068 intel::general::cmdGetShutdownPolicy, NULL,
4069 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004070
anil kumar appanaf945eee2019-09-25 23:29:11 +00004071 registerHandler(prioOemBase, intel::netFnGeneral,
4072 intel::general::cmdSetFanConfig, Privilege::User,
4073 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08004074
Vernon Mauery98bbf692019-09-16 11:14:59 -07004075 registerHandler(prioOemBase, intel::netFnGeneral,
4076 intel::general::cmdGetFanConfig, Privilege::User,
4077 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07004078
Vernon Mauery98bbf692019-09-16 11:14:59 -07004079 registerHandler(prioOemBase, intel::netFnGeneral,
4080 intel::general::cmdGetFanSpeedOffset, Privilege::User,
4081 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004082
Vernon Mauery98bbf692019-09-16 11:14:59 -07004083 registerHandler(prioOemBase, intel::netFnGeneral,
4084 intel::general::cmdSetFanSpeedOffset, Privilege::User,
4085 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004086
Vernon Mauery98bbf692019-09-16 11:14:59 -07004087 registerHandler(prioOemBase, intel::netFnGeneral,
4088 intel::general::cmdSetFscParameter, Privilege::User,
4089 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07004090
Vernon Mauery98bbf692019-09-16 11:14:59 -07004091 registerHandler(prioOemBase, intel::netFnGeneral,
4092 intel::general::cmdGetFscParameter, Privilege::User,
4093 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05304094
Vernon Mauery98bbf692019-09-16 11:14:59 -07004095 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4096 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
4097 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08004098
Vernon Mauery98bbf692019-09-16 11:14:59 -07004099 registerHandler(prioOemBase, intel::netFnGeneral,
4100 intel::general::cmdGetNmiStatus, Privilege::User,
4101 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08004102
Vernon Mauery98bbf692019-09-16 11:14:59 -07004103 registerHandler(prioOemBase, intel::netFnGeneral,
4104 intel::general::cmdSetNmiStatus, Privilege::Operator,
4105 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004106
Vernon Mauery98bbf692019-09-16 11:14:59 -07004107 registerHandler(prioOemBase, intel::netFnGeneral,
4108 intel::general::cmdGetEfiBootOptions, Privilege::User,
4109 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004110
Vernon Mauery98bbf692019-09-16 11:14:59 -07004111 registerHandler(prioOemBase, intel::netFnGeneral,
4112 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
4113 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304114
Vernon Mauery98bbf692019-09-16 11:14:59 -07004115 registerHandler(prioOemBase, intel::netFnGeneral,
4116 intel::general::cmdGetSecurityMode, Privilege::User,
4117 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304118
Vernon Mauery98bbf692019-09-16 11:14:59 -07004119 registerHandler(prioOemBase, intel::netFnGeneral,
4120 intel::general::cmdSetSecurityMode, Privilege::Admin,
4121 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004122
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00004123 registerHandler(prioOemBase, intel::netFnGeneral,
4124 intel::general::cmdGetLEDStatus, Privilege::Admin,
4125 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08004126
Vernon Mauery98bbf692019-09-16 11:14:59 -07004127 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
4128 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
4129 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
4130
4131 registerHandler(prioOemBase, intel::netFnGeneral,
4132 intel::general::cmdSetFaultIndication, Privilege::Operator,
4133 ipmiOEMSetFaultIndication);
4134
4135 registerHandler(prioOemBase, intel::netFnGeneral,
4136 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
4137 ipmiOEMSetCRConfig);
4138
4139 registerHandler(prioOemBase, intel::netFnGeneral,
4140 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
4141 ipmiOEMGetCRConfig);
4142
4143 registerHandler(prioOemBase, intel::netFnGeneral,
4144 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004145 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07004146
Vernon Mauery98bbf692019-09-16 11:14:59 -07004147 registerHandler(prioOemBase, intel::netFnGeneral,
4148 intel::general::cmdSetDimmOffset, Privilege::Operator,
4149 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07004150
Vernon Mauery98bbf692019-09-16 11:14:59 -07004151 registerHandler(prioOemBase, intel::netFnGeneral,
4152 intel::general::cmdGetDimmOffset, Privilege::Operator,
4153 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08004154
Cheng C Yang4e6ee152019-09-25 10:27:44 +08004155 registerHandler(prioOemBase, intel::netFnGeneral,
4156 intel::general::cmdGetPSUVersion, Privilege::User,
4157 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05304158
4159 registerHandler(prioOemBase, intel::netFnGeneral,
4160 intel::general::cmdGetBufferSize, Privilege::User,
4161 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00004162
4163 registerHandler(prioOemBase, intel::netFnGeneral,
4164 intel::general::cmdOEMGetReading, Privilege::User,
4165 ipmiOEMGetReading);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00004166
4167 registerHandler(prioOemBase, intel::netFnApp, intel::app::cmdPFRMailboxRead,
4168 Privilege::Admin, ipmiOEMReadPFRMailbox);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004169}
4170
4171} // namespace ipmi