blob: ac97fdb3dfb2dffd353b2afb06f16c5bfaf371ec [file] [log] [blame]
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Venturec2a07d42020-05-30 16:35:03 -070017#include "types.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070018#include "xyz/openbmc_project/Common/error.hpp"
Kuiying Wang45f04982018-12-26 09:23:08 +080019#include "xyz/openbmc_project/Led/Physical/server.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070020
Jayaprakash Mutyala94204162020-10-23 06:17:56 +000021#include <openssl/crypto.h>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080022#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080023
Chen Yugang7a04f3a2019-10-08 11:12:35 +080024#include <appcommands.hpp>
James Feist91244a62019-02-19 15:04:54 -080025#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080026#include <boost/process/child.hpp>
27#include <boost/process/io.hpp>
Yong Li0669d192019-05-06 14:01:46 +080028#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070029#include <commandutils.hpp>
Zhikui Rence4e73f2019-12-06 13:59:47 -080030#include <gpiod.hpp>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080031#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070032#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070033#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <phosphor-logging/log.hpp>
36#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053037#include <sdbusplus/message/types.hpp>
Chen Yugang97cf96e2019-11-01 08:55:11 +080038#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080039#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
40#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080041#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053042#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053043#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080044
James Feistfcd2d3a2020-05-28 10:38:15 -070045#include <array>
46#include <filesystem>
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};
270 std::vector<uint8_t> readBuf(0);
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;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800328 return IPMI_CC_REQ_DATA_LEN_INVALID;
329 }
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);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800337 return IPMI_CC_OK;
338 }
Jason M. Bills64796042018-10-03 16:51:55 -0700339 *dataLen = 0;
340 return IPMI_CC_RESPONSE_ERROR;
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;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800354 return IPMI_CC_REQ_DATA_LEN_INVALID;
355 }
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);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800374 return IPMI_CC_OK;
375}
376
Patrick Williams1bcced02024-08-16 15:20:24 -0400377ipmi::RspType<>
378 ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI, 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;
443 return IPMI_CC_REQ_DATA_LEN_INVALID;
444 }
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");
452 return IPMI_CC_INVALID_FIELD_REQUEST;
453 }
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;
464 return IPMI_CC_OK;
465}
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;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800694 return IPMI_CC_REQ_DATA_LEN_INVALID;
695 }
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.
703 return IPMI_CC_OK;
704}
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;
716 return IPMI_CC_REQ_DATA_LEN_INVALID;
717 }
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
734 return IPMI_CC_OK;
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
871 std::vector<uint8_t> dataReceived(0);
872 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;
897 return IPMI_CC_REQ_DATA_LEN_INVALID;
898 }
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
909 return IPMI_CC_OK;
910}
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;
1081 return IPMI_CC_REQ_DATA_LEN_INVALID;
1082 }
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()));
1115 return IPMI_CC_UNSPECIFIED_ERROR;
1116 }
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());
1124 return IPMI_CC_UNSPECIFIED_ERROR;
1125 }
1126
1127 *dataLen = sizeof(GetOEMShutdownPolicyRes);
1128 return IPMI_CC_OK;
1129}
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;
1147 return IPMI_CC_REQ_DATA_LEN_INVALID;
1148 }
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!");
1155 return IPMI_CC_INVALID_FIELD_REQUEST;
1156 }
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());
1182 return IPMI_CC_UNSPECIFIED_ERROR;
1183 }
1184
1185 return IPMI_CC_OK;
1186}
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{
1389 boost::process::child execProg(path);
1390 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));
1568 return IPMI_CC_REQ_DATA_LEN_INVALID;
1569 }
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;
1580 return IPMI_CC_REQ_DATA_LEN_INVALID;
1581 }
1582
1583 *dataLen = 0;
1584
1585 boost::process::ipstream is;
1586 std::vector<std::string> data;
1587 std::string line;
1588 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1589 boost::process::std_out > is);
1590
1591 while (c1.running() && std::getline(is, line) && !line.empty())
1592 {
1593 data.push_back(line);
1594 }
1595
1596 c1.wait();
1597 if (c1.exit_code())
1598 {
1599 phosphor::logging::log<phosphor::logging::level::ERR>(
1600 "CfgHostSerial:: error on execute",
1601 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1602 // Using the default value
1603 *resp = 0;
1604 }
1605 else
1606 {
1607 if (data.size() != 1)
1608 {
1609 phosphor::logging::log<phosphor::logging::level::ERR>(
1610 "CfgHostSerial:: error on read env");
1611 return IPMI_CC_UNSPECIFIED_ERROR;
1612 }
1613 try
1614 {
1615 unsigned long tmp = std::stoul(data[0]);
1616 if (tmp > std::numeric_limits<uint8_t>::max())
1617 {
1618 throw std::out_of_range("Out of range");
1619 }
1620 *resp = static_cast<uint8_t>(tmp);
1621 }
1622 catch (const std::invalid_argument& e)
1623 {
1624 phosphor::logging::log<phosphor::logging::level::ERR>(
1625 "invalid config ",
1626 phosphor::logging::entry("ERR=%s", e.what()));
1627 return IPMI_CC_UNSPECIFIED_ERROR;
1628 }
1629 catch (const std::out_of_range& e)
1630 {
1631 phosphor::logging::log<phosphor::logging::level::ERR>(
1632 "out_of_range config ",
1633 phosphor::logging::entry("ERR=%s", e.what()));
1634 return IPMI_CC_UNSPECIFIED_ERROR;
1635 }
1636 }
1637
1638 *dataLen = 1;
1639 break;
1640 }
1641 case setHostSerialCfgCmd:
1642 {
1643 if (*dataLen != sizeof(CfgHostSerialReq))
1644 {
1645 phosphor::logging::log<phosphor::logging::level::ERR>(
1646 "CfgHostSerial: invalid input len!");
1647 *dataLen = 0;
1648 return IPMI_CC_REQ_DATA_LEN_INVALID;
1649 }
1650
1651 *dataLen = 0;
1652
1653 if (req->parameter > HostSerialCfgParamMax)
1654 {
1655 phosphor::logging::log<phosphor::logging::level::ERR>(
1656 "CfgHostSerial: invalid input!");
1657 return IPMI_CC_INVALID_FIELD_REQUEST;
1658 }
1659
1660 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1661 std::to_string(req->parameter));
1662
1663 c1.wait();
1664 if (c1.exit_code())
1665 {
1666 phosphor::logging::log<phosphor::logging::level::ERR>(
1667 "CfgHostSerial:: error on execute",
1668 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1669 return IPMI_CC_UNSPECIFIED_ERROR;
1670 }
1671 break;
1672 }
1673 default:
1674 phosphor::logging::log<phosphor::logging::level::ERR>(
1675 "CfgHostSerial: invalid input!");
1676 *dataLen = 0;
1677 return IPMI_CC_INVALID_FIELD_REQUEST;
1678 }
1679
1680 return IPMI_CC_OK;
1681}
1682
James Feist91244a62019-02-19 15:04:54 -08001683constexpr const char* thermalModeInterface =
1684 "xyz.openbmc_project.Control.ThermalMode";
1685constexpr const char* thermalModePath =
1686 "/xyz/openbmc_project/control/thermal_mode";
1687
1688bool getFanProfileInterface(
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001689 sdbusplus::bus_t& bus,
Jason M. Bills0748c692022-09-08 15:34:08 -07001690 boost::container::flat_map<std::string, ipmi::DbusVariant>& resp)
James Feist91244a62019-02-19 15:04:54 -08001691{
1692 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1693 "GetAll");
1694 call.append(thermalModeInterface);
1695 try
1696 {
1697 auto data = bus.call(call);
1698 data.read(resp);
1699 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001700 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001701 {
1702 phosphor::logging::log<phosphor::logging::level::ERR>(
1703 "getFanProfileInterface: can't get thermal mode!",
1704 phosphor::logging::entry("ERR=%s", e.what()));
1705 return false;
1706 }
1707 return true;
1708}
1709
anil kumar appanaf945eee2019-09-25 23:29:11 +00001710/**@brief implements the OEM set fan config.
1711 * @param selectedFanProfile - fan profile to enable
1712 * @param reserved1
1713 * @param performanceMode - Performance/Acoustic mode
1714 * @param reserved2
1715 * @param setPerformanceMode - set Performance/Acoustic mode
1716 * @param setFanProfile - set fan profile
1717 *
1718 * @return IPMI completion code.
1719 **/
Vernon Mauerydcff1502022-09-28 11:12:46 -07001720ipmi::RspType<> ipmiOEMSetFanConfig(
1721 [[maybe_unused]] uint8_t selectedFanProfile, uint2_t reserved1,
1722 bool performanceMode, uint3_t reserved2, bool setPerformanceMode,
1723 [[maybe_unused]] bool setFanProfile, std::optional<uint8_t> dimmGroupId,
1724 [[maybe_unused]] std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001725{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001726 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001727 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001728 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001729 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301730
1731 if (dimmGroupId)
1732 {
1733 if (*dimmGroupId >= maxCPUNum)
1734 {
1735 return ipmi::responseInvalidFieldRequest();
1736 }
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001737 if (!cpuPresent("cpu" + std::to_string(*dimmGroupId)))
Joshi-Mansi619186d2020-01-27 19:16:03 +05301738 {
1739 return ipmi::responseInvalidFieldRequest();
1740 }
1741 }
1742
James Feist91244a62019-02-19 15:04:54 -08001743 // todo: tell bios to only send first 2 bytes
Jason M. Bills0748c692022-09-08 15:34:08 -07001744 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001745 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1746 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001747 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001748 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001749 }
1750
1751 std::vector<std::string>* supported =
1752 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1753 if (supported == nullptr)
1754 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001755 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001756 }
1757 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001758 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001759 {
James Feist91244a62019-02-19 15:04:54 -08001760 if (performanceMode)
1761 {
James Feist91244a62019-02-19 15:04:54 -08001762 if (std::find(supported->begin(), supported->end(),
1763 "Performance") != supported->end())
1764 {
1765 mode = "Performance";
1766 }
1767 }
1768 else
1769 {
James Feist91244a62019-02-19 15:04:54 -08001770 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1771 supported->end())
1772 {
1773 mode = "Acoustic";
1774 }
1775 }
1776 if (mode.empty())
1777 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001778 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001779 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001780
1781 try
1782 {
1783 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1784 thermalModeInterface, "Current", mode);
1785 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001786 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001787 {
1788 phosphor::logging::log<phosphor::logging::level::ERR>(
1789 "ipmiOEMSetFanConfig: can't set thermal mode!",
1790 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1791 return ipmi::responseResponseError();
1792 }
James Feist91244a62019-02-19 15:04:54 -08001793 }
1794
anil kumar appanaf945eee2019-09-25 23:29:11 +00001795 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001796}
1797
James Feist5b693632019-07-09 09:06:09 -07001798ipmi::RspType<uint8_t, // profile support map
1799 uint8_t, // fan control profile enable
1800 uint8_t, // flags
1801 uint32_t // dimm presence bit map
1802 >
1803 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001804{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301805 if (dimmGroupId >= maxCPUNum)
1806 {
1807 return ipmi::responseInvalidFieldRequest();
1808 }
1809
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001810 bool cpuStatus = cpuPresent("cpu" + std::to_string(dimmGroupId));
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301811
1812 if (!cpuStatus)
1813 {
1814 return ipmi::responseInvalidFieldRequest();
1815 }
1816
Jason M. Bills0748c692022-09-08 15:34:08 -07001817 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
James Feist91244a62019-02-19 15:04:54 -08001818
Vernon Mauery15419dd2019-05-24 09:40:30 -07001819 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1820 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001821 {
James Feist5b693632019-07-09 09:06:09 -07001822 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001823 }
1824
1825 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1826
1827 if (current == nullptr)
1828 {
1829 phosphor::logging::log<phosphor::logging::level::ERR>(
1830 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001831 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001832 }
1833 bool performance = (*current == "Performance");
1834
James Feist5b693632019-07-09 09:06:09 -07001835 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001836 if (performance)
1837 {
James Feist5b693632019-07-09 09:06:09 -07001838 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001839 }
1840
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001841 constexpr uint8_t fanControlDefaultProfile = 0x80;
1842 constexpr uint8_t fanControlProfileState = 0x00;
1843 constexpr uint32_t dimmPresenceBitmap = 0x00;
1844
1845 return ipmi::responseSuccess(fanControlDefaultProfile,
1846 fanControlProfileState, flags,
1847 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001848}
James Feist5f957ca2019-03-14 15:33:55 -07001849constexpr const char* cfmLimitSettingPath =
1850 "/xyz/openbmc_project/control/cfm_limit";
1851constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001852constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001853constexpr const size_t legacyPCHSensorNumber = 0x22;
1854constexpr const char* exitAirPathName = "Exit_Air";
1855constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001856constexpr const char* pidConfigurationIface =
1857 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001858
James Feist09f6b602019-08-08 11:30:03 -07001859static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001860{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001861 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001862 auto method =
1863 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1864 "/xyz/openbmc_project/object_mapper",
1865 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001866
James Feistacc8a4e2019-04-02 14:23:57 -07001867 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001868 std::string path;
1869 GetSubTreeType resp;
1870 try
1871 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001872 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001873 reply.read(resp);
1874 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001875 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001876 {
1877 phosphor::logging::log<phosphor::logging::level::ERR>(
1878 "ipmiOEMGetFscParameter: mapper error");
1879 };
Patrick Williams1bcced02024-08-16 15:20:24 -04001880 auto config =
1881 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1882 return pair.first.find(name) != std::string::npos;
1883 });
James Feistfaa4f222019-03-21 16:21:55 -07001884 if (config != resp.end())
1885 {
1886 path = std::move(config->first);
1887 }
1888 return path;
1889}
James Feist5f957ca2019-03-14 15:33:55 -07001890
James Feistacc8a4e2019-04-02 14:23:57 -07001891// flat map to make alphabetical
1892static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1893{
1894 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001895 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04001896 auto method =
1897 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1898 "/xyz/openbmc_project/object_mapper",
1899 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001900
1901 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1902 GetSubTreeType resp;
1903
1904 try
1905 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001906 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001907 reply.read(resp);
1908 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001909 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001910 {
1911 phosphor::logging::log<phosphor::logging::level::ERR>(
1912 "getFanConfigPaths: mapper error");
1913 };
1914 for (const auto& [path, objects] : resp)
1915 {
1916 if (objects.empty())
1917 {
1918 continue; // should be impossible
1919 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001920
1921 try
1922 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001923 ret.emplace(path,
1924 getAllDbusProperties(*dbus, objects[0].first, path,
1925 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001926 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001927 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001928 {
1929 phosphor::logging::log<phosphor::logging::level::ERR>(
1930 "getPidConfigs: can't get DbusProperties!",
1931 phosphor::logging::entry("ERR=%s", e.what()));
1932 }
James Feistacc8a4e2019-04-02 14:23:57 -07001933 }
1934 return ret;
1935}
1936
1937ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1938{
1939 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1940 if (data.empty())
1941 {
1942 return ipmi::responseResponseError();
1943 }
1944 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1945 for (const auto& [_, pid] : data)
1946 {
1947 auto findClass = pid.find("Class");
1948 if (findClass == pid.end())
1949 {
1950 phosphor::logging::log<phosphor::logging::level::ERR>(
1951 "ipmiOEMGetFscParameter: found illegal pid "
1952 "configurations");
1953 return ipmi::responseResponseError();
1954 }
1955 std::string type = std::get<std::string>(findClass->second);
1956 if (type == "fan")
1957 {
1958 auto findOutLimit = pid.find("OutLimitMin");
1959 if (findOutLimit == pid.end())
1960 {
1961 phosphor::logging::log<phosphor::logging::level::ERR>(
1962 "ipmiOEMGetFscParameter: found illegal pid "
1963 "configurations");
1964 return ipmi::responseResponseError();
1965 }
1966 // get the min out of all the offsets
1967 minOffset = std::min(
1968 minOffset,
1969 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1970 }
1971 }
1972 if (minOffset == std::numeric_limits<uint8_t>::max())
1973 {
1974 phosphor::logging::log<phosphor::logging::level::ERR>(
1975 "ipmiOEMGetFscParameter: found no fan configurations!");
1976 return ipmi::responseResponseError();
1977 }
1978
1979 return ipmi::responseSuccess(minOffset);
1980}
1981
1982ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1983{
Manish Baingbaa579f2021-10-08 22:30:32 +00001984 constexpr uint8_t maxFanSpeedOffset = 100;
1985 if (offset > maxFanSpeedOffset)
1986 {
1987 phosphor::logging::log<phosphor::logging::level::ERR>(
1988 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1989 return ipmi::responseInvalidFieldRequest();
1990 }
James Feistacc8a4e2019-04-02 14:23:57 -07001991 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1992 if (data.empty())
1993 {
James Feistacc8a4e2019-04-02 14:23:57 -07001994 phosphor::logging::log<phosphor::logging::level::ERR>(
1995 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1996 return ipmi::responseResponseError();
1997 }
1998
Vernon Mauery15419dd2019-05-24 09:40:30 -07001999 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002000 bool found = false;
2001 for (const auto& [path, pid] : data)
2002 {
2003 auto findClass = pid.find("Class");
2004 if (findClass == pid.end())
2005 {
James Feistacc8a4e2019-04-02 14:23:57 -07002006 phosphor::logging::log<phosphor::logging::level::ERR>(
2007 "ipmiOEMSetFanSpeedOffset: found illegal pid "
2008 "configurations");
2009 return ipmi::responseResponseError();
2010 }
2011 std::string type = std::get<std::string>(findClass->second);
2012 if (type == "fan")
2013 {
2014 auto findOutLimit = pid.find("OutLimitMin");
2015 if (findOutLimit == pid.end())
2016 {
James Feistacc8a4e2019-04-02 14:23:57 -07002017 phosphor::logging::log<phosphor::logging::level::ERR>(
2018 "ipmiOEMSetFanSpeedOffset: found illegal pid "
2019 "configurations");
2020 return ipmi::responseResponseError();
2021 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07002022 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07002023 path, pidConfigurationIface, "OutLimitMin",
2024 static_cast<double>(offset));
2025 found = true;
2026 }
2027 }
2028 if (!found)
2029 {
2030 phosphor::logging::log<phosphor::logging::level::ERR>(
2031 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
2032 return ipmi::responseResponseError();
2033 }
2034
2035 return ipmi::responseSuccess();
2036}
2037
2038ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
2039 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07002040{
2041 constexpr const size_t disableLimiting = 0x0;
2042
Vernon Mauery15419dd2019-05-24 09:40:30 -07002043 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002044 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002045 {
James Feist09f6b602019-08-08 11:30:03 -07002046 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07002047 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07002048 {
James Feist09f6b602019-08-08 11:30:03 -07002049 pathName = exitAirPathName;
2050 }
2051 else if (param1 == legacyPCHSensorNumber)
2052 {
2053 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07002054 }
2055 else
2056 {
James Feistacc8a4e2019-04-02 14:23:57 -07002057 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002058 }
James Feist09f6b602019-08-08 11:30:03 -07002059 std::string path = getConfigPath(pathName);
2060 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
2061 pidConfigurationIface, "SetPoint",
2062 static_cast<double>(param2));
2063 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07002064 }
James Feistacc8a4e2019-04-02 14:23:57 -07002065 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002066 {
James Feistacc8a4e2019-04-02 14:23:57 -07002067 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07002068
2069 // must be greater than 50 based on eps
2070 if (cfm < 50 && cfm != disableLimiting)
2071 {
James Feistacc8a4e2019-04-02 14:23:57 -07002072 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002073 }
2074
2075 try
2076 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002077 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07002078 cfmLimitIface, "Limit",
2079 static_cast<double>(cfm));
2080 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002081 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002082 {
2083 phosphor::logging::log<phosphor::logging::level::ERR>(
2084 "ipmiOEMSetFscParameter: can't set cfm setting!",
2085 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002086 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002087 }
James Feistacc8a4e2019-04-02 14:23:57 -07002088 return ipmi::responseSuccess();
2089 }
2090 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2091 {
James Feistacc8a4e2019-04-02 14:23:57 -07002092 uint8_t requestedDomainMask = param1;
2093 boost::container::flat_map data = getPidConfigs();
2094 if (data.empty())
2095 {
James Feistacc8a4e2019-04-02 14:23:57 -07002096 phosphor::logging::log<phosphor::logging::level::ERR>(
2097 "ipmiOEMSetFscParameter: found no pid configurations!");
2098 return ipmi::responseResponseError();
2099 }
2100 size_t count = 0;
2101 for (const auto& [path, pid] : data)
2102 {
2103 auto findClass = pid.find("Class");
2104 if (findClass == pid.end())
2105 {
James Feistacc8a4e2019-04-02 14:23:57 -07002106 phosphor::logging::log<phosphor::logging::level::ERR>(
2107 "ipmiOEMSetFscParameter: found illegal pid "
2108 "configurations");
2109 return ipmi::responseResponseError();
2110 }
2111 std::string type = std::get<std::string>(findClass->second);
2112 if (type == "fan")
2113 {
2114 if (requestedDomainMask & (1 << count))
2115 {
2116 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002117 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07002118 pidConfigurationIface, "OutLimitMax",
2119 static_cast<double>(param2));
2120 }
2121 count++;
2122 }
2123 }
2124 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07002125 }
2126 else
2127 {
2128 // todo other command parts possibly
2129 // tcontrol is handled in peci now
2130 // fan speed offset not implemented yet
2131 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002132 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002133 }
2134}
2135
James Feistacc8a4e2019-04-02 14:23:57 -07002136ipmi::RspType<
2137 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2138 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002139{
James Feist09f6b602019-08-08 11:30:03 -07002140 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002141
Vernon Mauery15419dd2019-05-24 09:40:30 -07002142 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002143 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002144 {
James Feistacc8a4e2019-04-02 14:23:57 -07002145 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002146 {
James Feistacc8a4e2019-04-02 14:23:57 -07002147 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002148 }
2149
James Feist09f6b602019-08-08 11:30:03 -07002150 std::string pathName;
2151
2152 if (*param == legacyExitAirSensorNumber)
2153 {
2154 pathName = exitAirPathName;
2155 }
2156 else if (*param == legacyPCHSensorNumber)
2157 {
2158 pathName = pchPathName;
2159 }
2160 else
James Feistfaa4f222019-03-21 16:21:55 -07002161 {
James Feistacc8a4e2019-04-02 14:23:57 -07002162 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002163 }
James Feist09f6b602019-08-08 11:30:03 -07002164
2165 uint8_t setpoint = legacyDefaultSetpoint;
2166 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002167 if (path.size())
2168 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002169 Value val = ipmi::getDbusProperty(
2170 *dbus, "xyz.openbmc_project.EntityManager", path,
2171 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002172 setpoint = std::floor(std::get<double>(val) + 0.5);
2173 }
2174
2175 // old implementation used to return the "default" and current, we
2176 // don't make the default readily available so just make both the
2177 // same
James Feistfaa4f222019-03-21 16:21:55 -07002178
James Feistacc8a4e2019-04-02 14:23:57 -07002179 return ipmi::responseSuccess(
2180 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002181 }
James Feistacc8a4e2019-04-02 14:23:57 -07002182 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2183 {
2184 constexpr const size_t maxDomainCount = 8;
2185
2186 if (!param)
2187 {
2188 return ipmi::responseReqDataLenInvalid();
2189 }
2190 uint8_t requestedDomain = *param;
2191 if (requestedDomain >= maxDomainCount)
2192 {
2193 return ipmi::responseInvalidFieldRequest();
2194 }
2195
2196 boost::container::flat_map data = getPidConfigs();
2197 if (data.empty())
2198 {
2199 phosphor::logging::log<phosphor::logging::level::ERR>(
2200 "ipmiOEMGetFscParameter: found no pid configurations!");
2201 return ipmi::responseResponseError();
2202 }
2203 size_t count = 0;
2204 for (const auto& [_, pid] : data)
2205 {
2206 auto findClass = pid.find("Class");
2207 if (findClass == pid.end())
2208 {
2209 phosphor::logging::log<phosphor::logging::level::ERR>(
2210 "ipmiOEMGetFscParameter: found illegal pid "
2211 "configurations");
2212 return ipmi::responseResponseError();
2213 }
2214 std::string type = std::get<std::string>(findClass->second);
2215 if (type == "fan")
2216 {
2217 if (requestedDomain == count)
2218 {
2219 auto findOutLimit = pid.find("OutLimitMax");
2220 if (findOutLimit == pid.end())
2221 {
2222 phosphor::logging::log<phosphor::logging::level::ERR>(
2223 "ipmiOEMGetFscParameter: found illegal pid "
2224 "configurations");
2225 return ipmi::responseResponseError();
2226 }
2227
2228 return ipmi::responseSuccess(
2229 static_cast<uint8_t>(std::floor(
2230 std::get<double>(findOutLimit->second) + 0.5)));
2231 }
2232 else
2233 {
2234 count++;
2235 }
2236 }
2237 }
2238
2239 return ipmi::responseInvalidFieldRequest();
2240 }
2241 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002242 {
James Feist5f957ca2019-03-14 15:33:55 -07002243 /*
2244 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002245 previous behavior didn't seem to prevent this, ignore the check for
2246 now.
James Feist5f957ca2019-03-14 15:33:55 -07002247
James Feistacc8a4e2019-04-02 14:23:57 -07002248 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002249 {
2250 phosphor::logging::log<phosphor::logging::level::ERR>(
2251 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002252 return IPMI_CC_REQ_DATA_LEN_INVALID;
2253 }
2254 */
2255 Value cfmLimit;
2256 Value cfmMaximum;
2257 try
2258 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002259 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002260 cfmLimitSettingPath, cfmLimitIface,
2261 "Limit");
2262 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002263 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002264 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2265 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002266 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002267 {
2268 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002269 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002270 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002271 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002272 }
2273
James Feistacc8a4e2019-04-02 14:23:57 -07002274 double cfmMax = std::get<double>(cfmMaximum);
2275 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002276
James Feistacc8a4e2019-04-02 14:23:57 -07002277 cfmLim = std::floor(cfmLim + 0.5);
2278 cfmMax = std::floor(cfmMax + 0.5);
2279 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2280 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002281
James Feistacc8a4e2019-04-02 14:23:57 -07002282 return ipmi::responseSuccess(
2283 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002284 }
James Feistacc8a4e2019-04-02 14:23:57 -07002285
James Feist5f957ca2019-03-14 15:33:55 -07002286 else
2287 {
2288 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002289 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002290 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002291 }
2292}
2293
Jason M. Bills0748c692022-09-08 15:34:08 -07002294using crConfigVariant = ipmi::DbusVariant;
Cheng C Yang773703a2019-08-15 09:41:11 +08002295
Vernon Mauerydcff1502022-09-28 11:12:46 -07002296int setCRConfig(ipmi::Context::ptr& ctx, const std::string& property,
Cheng C Yang773703a2019-08-15 09:41:11 +08002297 const crConfigVariant& value,
Vernon Mauerydcff1502022-09-28 11:12:46 -07002298 [[maybe_unused]] std::chrono::microseconds timeout =
2299 ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002300{
2301 boost::system::error_code ec;
2302 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002303 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002304 "/xyz/openbmc_project/control/power_supply_redundancy",
2305 "org.freedesktop.DBus.Properties", "Set",
2306 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2307 if (ec)
2308 {
2309 phosphor::logging::log<phosphor::logging::level::ERR>(
2310 "Failed to set dbus property to cold redundancy");
2311 return -1;
2312 }
2313
2314 return 0;
2315}
2316
Kuiying Wange45333a2020-07-22 22:06:37 +08002317int getCRConfig(
Vernon Mauerydcff1502022-09-28 11:12:46 -07002318 ipmi::Context::ptr& ctx, const std::string& property,
2319 crConfigVariant& value,
Kuiying Wange45333a2020-07-22 22:06:37 +08002320 const std::string& service = "xyz.openbmc_project.PSURedundancy",
Vernon Mauerydcff1502022-09-28 11:12:46 -07002321 [[maybe_unused]] std::chrono::microseconds timeout =
2322 ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002323{
2324 boost::system::error_code ec;
2325 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002326 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002327 "/xyz/openbmc_project/control/power_supply_redundancy",
2328 "org.freedesktop.DBus.Properties", "Get",
2329 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2330 if (ec)
2331 {
2332 phosphor::logging::log<phosphor::logging::level::ERR>(
2333 "Failed to get dbus property to cold redundancy");
2334 return -1;
2335 }
2336 return 0;
2337}
2338
2339uint8_t getPSUCount(void)
2340{
2341 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2342 ipmi::Value num;
2343 try
2344 {
2345 num = ipmi::getDbusProperty(
2346 *dbus, "xyz.openbmc_project.PSURedundancy",
2347 "/xyz/openbmc_project/control/power_supply_redundancy",
2348 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2349 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002350 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002351 {
2352 phosphor::logging::log<phosphor::logging::level::ERR>(
2353 "Failed to get PSUNumber property from dbus interface");
2354 return 0;
2355 }
2356 uint8_t* pNum = std::get_if<uint8_t>(&num);
2357 if (!pNum)
2358 {
2359 phosphor::logging::log<phosphor::logging::level::ERR>(
2360 "Error to get PSU Number");
2361 return 0;
2362 }
2363 return *pNum;
2364}
2365
2366bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2367{
2368 if (conf.size() < num)
2369 {
2370 phosphor::logging::log<phosphor::logging::level::ERR>(
2371 "Invalid PSU Ranking");
2372 return false;
2373 }
2374 std::set<uint8_t> confSet;
2375 for (uint8_t i = 0; i < num; i++)
2376 {
2377 if (conf[i] > num)
2378 {
2379 phosphor::logging::log<phosphor::logging::level::ERR>(
2380 "PSU Ranking is larger than current PSU number");
2381 return false;
2382 }
2383 confSet.emplace(conf[i]);
2384 }
2385
2386 if (confSet.size() != num)
2387 {
2388 phosphor::logging::log<phosphor::logging::level::ERR>(
2389 "duplicate PSU Ranking");
2390 return false;
2391 }
2392 return true;
2393}
2394
2395enum class crParameter
2396{
2397 crStatus = 0,
2398 crFeature = 1,
2399 rotationFeature = 2,
2400 rotationAlgo = 3,
2401 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002402 numOfPSU = 5,
2403 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002404};
2405
2406constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2407static const constexpr uint32_t oneDay = 0x15180;
2408static const constexpr uint32_t oneMonth = 0xf53700;
2409static const constexpr uint8_t userSpecific = 0x01;
2410static const constexpr uint8_t crSetCompleted = 0;
Patrick Williams1bcced02024-08-16 15:20:24 -04002411ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(
2412 ipmi::Context::ptr& ctx, uint8_t parameter, ipmi::message::Payload& payload)
Cheng C Yang773703a2019-08-15 09:41:11 +08002413{
2414 switch (static_cast<crParameter>(parameter))
2415 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002416 case crParameter::rotationFeature:
2417 {
2418 uint8_t param1;
2419 if (payload.unpack(param1) || !payload.fullyUnpacked())
2420 {
2421 return ipmi::responseReqDataLenInvalid();
2422 }
2423 // Rotation Enable can only be true or false
2424 if (param1 > 1)
2425 {
2426 return ipmi::responseInvalidFieldRequest();
2427 }
2428 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2429 {
2430 return ipmi::responseResponseError();
2431 }
2432 break;
2433 }
2434 case crParameter::rotationAlgo:
2435 {
2436 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2437 std::string algoName;
2438 uint8_t param1;
2439 if (payload.unpack(param1))
2440 {
2441 return ipmi::responseReqDataLenInvalid();
2442 }
2443 switch (param1)
2444 {
2445 case 0:
2446 algoName = "xyz.openbmc_project.Control."
2447 "PowerSupplyRedundancy.Algo.bmcSpecific";
2448 break;
2449 case 1:
2450 algoName = "xyz.openbmc_project.Control."
2451 "PowerSupplyRedundancy.Algo.userSpecific";
2452 break;
2453 default:
2454 return ipmi::responseInvalidFieldRequest();
2455 }
2456 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2457 {
2458 return ipmi::responseResponseError();
2459 }
2460
2461 uint8_t numberOfPSU = getPSUCount();
2462 if (!numberOfPSU)
2463 {
2464 return ipmi::responseResponseError();
2465 }
2466 std::vector<uint8_t> rankOrder;
2467
2468 if (param1 == userSpecific)
2469 {
2470 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2471 {
2472 ipmi::responseReqDataLenInvalid();
2473 }
Yong Li83315132019-10-23 17:42:24 +08002474 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002475 {
2476 return ipmi::responseReqDataLenInvalid();
2477 }
2478
2479 if (!validateCRAlgo(rankOrder, numberOfPSU))
2480 {
2481 return ipmi::responseInvalidFieldRequest();
2482 }
2483 }
2484 else
2485 {
2486 if (rankOrder.size() > 0)
2487 {
2488 return ipmi::responseReqDataLenInvalid();
2489 }
2490 for (uint8_t i = 1; i <= numberOfPSU; i++)
2491 {
2492 rankOrder.emplace_back(i);
2493 }
2494 }
2495 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2496 {
2497 return ipmi::responseResponseError();
2498 }
2499 break;
2500 }
2501 case crParameter::rotationPeriod:
2502 {
2503 // Minimum Rotation period is One day (86400 seconds) and Max
2504 // Rotation Period is 6 month (0xf53700 seconds)
2505 uint32_t period;
2506 if (payload.unpack(period) || !payload.fullyUnpacked())
2507 {
2508 return ipmi::responseReqDataLenInvalid();
2509 }
2510 if ((period < oneDay) || (period > oneMonth))
2511 {
2512 return ipmi::responseInvalidFieldRequest();
2513 }
2514 if (setCRConfig(ctx, "PeriodOfRotation", period))
2515 {
2516 return ipmi::responseResponseError();
2517 }
2518 break;
2519 }
2520 default:
2521 {
2522 return ipmi::response(ccParameterNotSupported);
2523 }
2524 }
2525
Cheng C Yang773703a2019-08-15 09:41:11 +08002526 return ipmi::responseSuccess(crSetCompleted);
2527}
2528
Yong Li83315132019-10-23 17:42:24 +08002529ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Vernon Mauerydcff1502022-09-28 11:12:46 -07002530 ipmiOEMGetCRConfig(ipmi::Context::ptr& ctx, uint8_t parameter)
Cheng C Yang773703a2019-08-15 09:41:11 +08002531{
2532 crConfigVariant value;
2533 switch (static_cast<crParameter>(parameter))
2534 {
2535 case crParameter::crStatus:
2536 {
2537 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2538 {
2539 return ipmi::responseResponseError();
2540 }
2541 std::string* pStatus = std::get_if<std::string>(&value);
2542 if (!pStatus)
2543 {
2544 phosphor::logging::log<phosphor::logging::level::ERR>(
2545 "Error to get ColdRedundancyStatus property");
2546 return ipmi::responseResponseError();
2547 }
2548 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2549 auto status =
2550 server::PowerSupplyRedundancy::convertStatusFromString(
2551 *pStatus);
2552 switch (status)
2553 {
2554 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002555 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002556 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002557
2558 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002559 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002560 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002561 default:
2562 phosphor::logging::log<phosphor::logging::level::ERR>(
2563 "Error to get valid status");
2564 return ipmi::responseResponseError();
2565 }
2566 }
2567 case crParameter::crFeature:
2568 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002569 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002570 {
2571 return ipmi::responseResponseError();
2572 }
2573 bool* pResponse = std::get_if<bool>(&value);
2574 if (!pResponse)
2575 {
2576 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002577 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002578 return ipmi::responseResponseError();
2579 }
2580
Cheng C Yangf41e3342019-09-10 04:47:23 +08002581 return ipmi::responseSuccess(parameter,
2582 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002583 }
2584 case crParameter::rotationFeature:
2585 {
2586 if (getCRConfig(ctx, "RotationEnabled", value))
2587 {
2588 return ipmi::responseResponseError();
2589 }
2590 bool* pResponse = std::get_if<bool>(&value);
2591 if (!pResponse)
2592 {
2593 phosphor::logging::log<phosphor::logging::level::ERR>(
2594 "Error to get RotationEnabled property");
2595 return ipmi::responseResponseError();
2596 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002597 return ipmi::responseSuccess(parameter,
2598 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002599 }
2600 case crParameter::rotationAlgo:
2601 {
2602 if (getCRConfig(ctx, "RotationAlgorithm", value))
2603 {
2604 return ipmi::responseResponseError();
2605 }
2606
2607 std::string* pAlgo = std::get_if<std::string>(&value);
2608 if (!pAlgo)
2609 {
2610 phosphor::logging::log<phosphor::logging::level::ERR>(
2611 "Error to get RotationAlgorithm property");
2612 return ipmi::responseResponseError();
2613 }
Yong Li83315132019-10-23 17:42:24 +08002614 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002615 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2616 auto algo =
2617 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002618
Cheng C Yang773703a2019-08-15 09:41:11 +08002619 switch (algo)
2620 {
2621 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002622 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002623 break;
2624 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002625 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002626 break;
2627 default:
2628 phosphor::logging::log<phosphor::logging::level::ERR>(
2629 "Error to get valid algo");
2630 return ipmi::responseResponseError();
2631 }
2632
2633 if (getCRConfig(ctx, "RotationRankOrder", value))
2634 {
2635 return ipmi::responseResponseError();
2636 }
2637 std::vector<uint8_t>* pResponse =
2638 std::get_if<std::vector<uint8_t>>(&value);
2639 if (!pResponse)
2640 {
2641 phosphor::logging::log<phosphor::logging::level::ERR>(
2642 "Error to get RotationRankOrder property");
2643 return ipmi::responseResponseError();
2644 }
Yong Li83315132019-10-23 17:42:24 +08002645
Cheng C Yang773703a2019-08-15 09:41:11 +08002646 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002647 std::back_inserter(response));
2648
Cheng C Yangf41e3342019-09-10 04:47:23 +08002649 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002650 }
2651 case crParameter::rotationPeriod:
2652 {
2653 if (getCRConfig(ctx, "PeriodOfRotation", value))
2654 {
2655 return ipmi::responseResponseError();
2656 }
2657 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2658 if (!pResponse)
2659 {
2660 phosphor::logging::log<phosphor::logging::level::ERR>(
2661 "Error to get RotationAlgorithm property");
2662 return ipmi::responseResponseError();
2663 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002664 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002665 }
2666 case crParameter::numOfPSU:
2667 {
2668 uint8_t numberOfPSU = getPSUCount();
2669 if (!numberOfPSU)
2670 {
2671 return ipmi::responseResponseError();
2672 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002673 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002674 }
Yong Li19445ab2019-12-20 18:25:29 +08002675 case crParameter::rotationRankOrderEffective:
2676 {
2677 if (getCRConfig(ctx, "RotationRankOrder", value,
2678 "xyz.openbmc_project.PSURedundancy"))
2679 {
2680 return ipmi::responseResponseError();
2681 }
2682 std::vector<uint8_t>* pResponse =
2683 std::get_if<std::vector<uint8_t>>(&value);
2684 if (!pResponse)
2685 {
2686 phosphor::logging::log<phosphor::logging::level::ERR>(
2687 "Error to get effective RotationRankOrder property");
2688 return ipmi::responseResponseError();
2689 }
2690 return ipmi::responseSuccess(parameter, *pResponse);
2691 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002692 default:
2693 {
2694 return ipmi::response(ccParameterNotSupported);
2695 }
2696 }
2697}
2698
Patrick Williams1bcced02024-08-16 15:20:24 -04002699ipmi::RspType<> ipmiOEMSetFaultIndication(
2700 uint8_t sourceId, uint8_t faultType, uint8_t faultState, uint8_t faultGroup,
2701 std::array<uint8_t, 8>& ledStateData)
Zhu, Yungebe560b02019-04-21 21:19:21 -04002702{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002703 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2704 static const std::array<std::string, maxFaultType> faultNames = {
2705 "faultFan", "faultTemp", "faultPower",
2706 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002707
2708 constexpr uint8_t maxFaultSource = 0x4;
2709 constexpr uint8_t skipLEDs = 0xFF;
2710 constexpr uint8_t pinSize = 64;
2711 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002712 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002713
Zhikui Rence4e73f2019-12-06 13:59:47 -08002714 // same pin names need to be defined in dts file
2715 static const std::array<std::array<std::string, groupSize>, groupNum>
2716 faultLedPinNames = {{
2717 "LED_CPU1_CH1_DIMM1_FAULT",
2718 "LED_CPU1_CH1_DIMM2_FAULT",
2719 "LED_CPU1_CH2_DIMM1_FAULT",
2720 "LED_CPU1_CH2_DIMM2_FAULT",
2721 "LED_CPU1_CH3_DIMM1_FAULT",
2722 "LED_CPU1_CH3_DIMM2_FAULT",
2723 "LED_CPU1_CH4_DIMM1_FAULT",
2724 "LED_CPU1_CH4_DIMM2_FAULT",
2725 "LED_CPU1_CH5_DIMM1_FAULT",
2726 "LED_CPU1_CH5_DIMM2_FAULT",
2727 "LED_CPU1_CH6_DIMM1_FAULT",
2728 "LED_CPU1_CH6_DIMM2_FAULT",
2729 "",
2730 "",
2731 "",
2732 "", // end of group1
2733 "LED_CPU2_CH1_DIMM1_FAULT",
2734 "LED_CPU2_CH1_DIMM2_FAULT",
2735 "LED_CPU2_CH2_DIMM1_FAULT",
2736 "LED_CPU2_CH2_DIMM2_FAULT",
2737 "LED_CPU2_CH3_DIMM1_FAULT",
2738 "LED_CPU2_CH3_DIMM2_FAULT",
2739 "LED_CPU2_CH4_DIMM1_FAULT",
2740 "LED_CPU2_CH4_DIMM2_FAULT",
2741 "LED_CPU2_CH5_DIMM1_FAULT",
2742 "LED_CPU2_CH5_DIMM2_FAULT",
2743 "LED_CPU2_CH6_DIMM1_FAULT",
2744 "LED_CPU2_CH6_DIMM2_FAULT",
2745 "",
2746 "",
2747 "",
2748 "", // endof group2
2749 "LED_CPU3_CH1_DIMM1_FAULT",
2750 "LED_CPU3_CH1_DIMM2_FAULT",
2751 "LED_CPU3_CH2_DIMM1_FAULT",
2752 "LED_CPU3_CH2_DIMM2_FAULT",
2753 "LED_CPU3_CH3_DIMM1_FAULT",
2754 "LED_CPU3_CH3_DIMM2_FAULT",
2755 "LED_CPU3_CH4_DIMM1_FAULT",
2756 "LED_CPU3_CH4_DIMM2_FAULT",
2757 "LED_CPU3_CH5_DIMM1_FAULT",
2758 "LED_CPU3_CH5_DIMM2_FAULT",
2759 "LED_CPU3_CH6_DIMM1_FAULT",
2760 "LED_CPU3_CH6_DIMM2_FAULT",
2761 "",
2762 "",
2763 "",
2764 "", // end of group3
2765 "LED_CPU4_CH1_DIMM1_FAULT",
2766 "LED_CPU4_CH1_DIMM2_FAULT",
2767 "LED_CPU4_CH2_DIMM1_FAULT",
2768 "LED_CPU4_CH2_DIMM2_FAULT",
2769 "LED_CPU4_CH3_DIMM1_FAULT",
2770 "LED_CPU4_CH3_DIMM2_FAULT",
2771 "LED_CPU4_CH4_DIMM1_FAULT",
2772 "LED_CPU4_CH4_DIMM2_FAULT",
2773 "LED_CPU4_CH5_DIMM1_FAULT",
2774 "LED_CPU4_CH5_DIMM2_FAULT",
2775 "LED_CPU4_CH6_DIMM1_FAULT",
2776 "LED_CPU4_CH6_DIMM2_FAULT",
2777 "",
2778 "",
2779 "",
2780 "", // end of group4
2781 "LED_FAN1_FAULT",
2782 "LED_FAN2_FAULT",
2783 "LED_FAN3_FAULT",
2784 "LED_FAN4_FAULT",
2785 "LED_FAN5_FAULT",
2786 "LED_FAN6_FAULT",
2787 "LED_FAN7_FAULT",
2788 "LED_FAN8_FAULT",
2789 "",
2790 "",
2791 "",
2792 "",
2793 "",
2794 "",
2795 "",
2796 "" // end of group5
2797 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002798
Zhikui Rence4e73f2019-12-06 13:59:47 -08002799 // Validate the source, fault type --
2800 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2801 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2802 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2803 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2804 // definition differs based on fault type (Byte 2)
2805 // Type Fan=> Group: 0=FanGroupID, FF-not used
2806 // Byte 5-11 00h, not used
2807 // Byte12 FanLedState [7:0]-Fans 7:0
2808 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2809 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2810 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2811 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2812 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2813 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2814 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2815 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002816 if ((sourceId >= maxFaultSource) ||
2817 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2818 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2819 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2820 {
2821 return ipmi::responseParmOutOfRange();
2822 }
2823
Zhikui Rence4e73f2019-12-06 13:59:47 -08002824 size_t pinGroupOffset = 0;
2825 size_t pinGroupMax = pinSize / groupSize;
2826 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002827 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002828 pinGroupOffset = 4;
2829 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002830 }
2831
2832 switch (RemoteFaultType(faultType))
2833 {
2834 case (RemoteFaultType::fan):
2835 case (RemoteFaultType::memory):
2836 {
2837 if (faultGroup == skipLEDs)
2838 {
2839 return ipmi::responseSuccess();
2840 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002841 // calculate led state bit filed count, each byte has 8bits
2842 // the maximum bits will be 8 * 8 bits
2843 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002844
2845 // assemble ledState
2846 uint64_t ledState = 0;
2847 bool hasError = false;
Vernon Mauerydcff1502022-09-28 11:12:46 -07002848 for (size_t i = 0; i < sizeof(ledStateData); i++)
Zhu, Yungebe560b02019-04-21 21:19:21 -04002849 {
2850 ledState = (uint64_t)(ledState << 8);
2851 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2852 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002853 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002854
Vernon Mauerydcff1502022-09-28 11:12:46 -07002855 for (size_t group = 0; group < pinGroupMax; group++)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002856 {
2857 for (int i = 0; i < groupSize; i++)
2858 { // skip non-existing pins
2859 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2860 {
2861 continue;
2862 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002863
Zhikui Rence4e73f2019-12-06 13:59:47 -08002864 gpiod::line line = gpiod::find_line(
2865 faultLedPinNames[group + pinGroupOffset][i]);
2866 if (!line)
2867 {
2868 phosphor::logging::log<phosphor::logging::level::ERR>(
2869 "Not Find Led Gpio Device!",
2870 phosphor::logging::entry(
2871 "DEVICE=%s",
2872 faultLedPinNames[group + pinGroupOffset][i]
2873 .c_str()));
2874 hasError = true;
2875 continue;
2876 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002877
Zhikui Rence4e73f2019-12-06 13:59:47 -08002878 bool activeHigh =
2879 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2880 try
2881 {
2882 line.request(
2883 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2884 activeHigh
2885 ? 0
2886 : gpiod::line_request::FLAG_ACTIVE_LOW});
2887 line.set_value(ledStateBits[i + group * groupSize]);
2888 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002889 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002890 {
2891 phosphor::logging::log<phosphor::logging::level::ERR>(
2892 "Error write Led Gpio Device!",
2893 phosphor::logging::entry(
2894 "DEVICE=%s",
2895 faultLedPinNames[group + pinGroupOffset][i]
2896 .c_str()));
2897 hasError = true;
2898 continue;
2899 }
2900 } // for int i
2901 }
2902 if (hasError)
2903 {
2904 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002905 }
2906 break;
2907 }
2908 default:
2909 {
2910 // now only support two fault types
2911 return ipmi::responseParmOutOfRange();
2912 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002913 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002914 return ipmi::responseSuccess();
2915}
2916
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302917ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2918{
2919 uint8_t prodId = 0;
2920 try
2921 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002922 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302923 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002924 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302925 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2926 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002927 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302928 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2929 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302930 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2931 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002932 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302933 {
2934 phosphor::logging::log<phosphor::logging::level::ERR>(
2935 "ipmiOEMReadBoardProductId: Product ID read failed!",
2936 phosphor::logging::entry("ERR=%s", e.what()));
2937 }
2938 return ipmi::responseSuccess(prodId);
2939}
2940
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302941/** @brief implements the get security mode command
2942 * @param ctx - ctx pointer
2943 *
2944 * @returns IPMI completion code with following data
2945 * - restriction mode value - As specified in
2946 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2947 * - special mode value - As specified in
2948 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2949 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07002950ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr& ctx)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302951{
2952 namespace securityNameSpace =
2953 sdbusplus::xyz::openbmc_project::Control::Security::server;
2954 uint8_t restrictionModeValue = 0;
2955 uint8_t specialModeValue = 0;
2956
2957 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07002958 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07002959 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302960 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2961 restricionModeProperty);
2962 if (ec)
2963 {
2964 phosphor::logging::log<phosphor::logging::level::ERR>(
2965 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2966 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2967 return ipmi::responseUnspecifiedError();
2968 }
2969 restrictionModeValue = static_cast<uint8_t>(
2970 securityNameSpace::RestrictionMode::convertModesFromString(
2971 std::get<std::string>(varRestrMode)));
Jason M. Bills0748c692022-09-08 15:34:08 -07002972 auto varSpecialMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
2973 ctx->yield, ec, specialModeService, specialModeBasePath,
2974 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2975 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302976 if (ec)
2977 {
2978 phosphor::logging::log<phosphor::logging::level::ERR>(
2979 "ipmiGetSecurityMode: failed to get SpecialMode property",
2980 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2981 // fall through, let us not worry about SpecialMode property, which is
2982 // not required in user scenario
2983 }
2984 else
2985 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302986 specialModeValue = static_cast<uint8_t>(
2987 securityNameSpace::SpecialMode::convertModesFromString(
2988 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302989 }
2990 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2991}
2992
2993/** @brief implements the set security mode command
2994 * Command allows to upgrade the restriction mode and won't allow
2995 * to downgrade from system interface
2996 * @param ctx - ctx pointer
2997 * @param restrictionMode - restriction mode value to be set.
2998 *
2999 * @returns IPMI completion code
3000 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07003001ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr& ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303002 uint8_t restrictionMode,
3003 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303004{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303005#ifndef BMC_VALIDATION_UNSECURE_FEATURE
3006 if (specialMode)
3007 {
3008 return ipmi::responseReqDataLenInvalid();
3009 }
3010#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303011 namespace securityNameSpace =
3012 sdbusplus::xyz::openbmc_project::Control::Security::server;
3013
3014 ChannelInfo chInfo;
3015 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
3016 {
3017 phosphor::logging::log<phosphor::logging::level::ERR>(
3018 "ipmiSetSecurityMode: Failed to get Channel Info",
3019 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
3020 return ipmi::responseUnspecifiedError();
3021 }
3022 auto reqMode =
3023 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
3024
3025 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
3026 (reqMode >
3027 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
3028 {
3029 return ipmi::responseInvalidFieldRequest();
3030 }
3031
3032 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07003033 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07003034 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303035 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
3036 restricionModeProperty);
3037 if (ec)
3038 {
3039 phosphor::logging::log<phosphor::logging::level::ERR>(
3040 "ipmiSetSecurityMode: failed to get RestrictionMode property",
3041 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3042 return ipmi::responseUnspecifiedError();
3043 }
3044 auto currentRestrictionMode =
3045 securityNameSpace::RestrictionMode::convertModesFromString(
3046 std::get<std::string>(varRestrMode));
3047
3048 if (chInfo.mediumType !=
3049 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
3050 currentRestrictionMode > reqMode)
3051 {
3052 phosphor::logging::log<phosphor::logging::level::ERR>(
3053 "ipmiSetSecurityMode - Downgrading security mode not supported "
3054 "through system interface",
3055 phosphor::logging::entry(
3056 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
3057 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
3058 return ipmi::responseCommandNotAvailable();
3059 }
3060
3061 ec.clear();
3062 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07003063 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303064 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
3065 restricionModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003066 static_cast<ipmi::DbusVariant>(
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303067 securityNameSpace::convertForMessage(reqMode)));
3068
3069 if (ec)
3070 {
3071 phosphor::logging::log<phosphor::logging::level::ERR>(
3072 "ipmiSetSecurityMode: failed to set RestrictionMode property",
3073 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3074 return ipmi::responseUnspecifiedError();
3075 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303076
3077#ifdef BMC_VALIDATION_UNSECURE_FEATURE
3078 if (specialMode)
3079 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00003080 constexpr uint8_t mfgMode = 0x01;
3081 // Manufacturing mode is reserved. So can't enable this mode.
3082 if (specialMode.value() == mfgMode)
3083 {
3084 phosphor::logging::log<phosphor::logging::level::INFO>(
3085 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
3086 return ipmi::responseInvalidFieldRequest();
3087 }
3088
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303089 ec.clear();
3090 ctx->bus->yield_method_call<>(
3091 ctx->yield, ec, specialModeService, specialModeBasePath,
3092 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
3093 specialModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003094 static_cast<ipmi::DbusVariant>(securityNameSpace::convertForMessage(
3095 static_cast<securityNameSpace::SpecialMode::Modes>(
3096 specialMode.value()))));
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303097
3098 if (ec)
3099 {
3100 phosphor::logging::log<phosphor::logging::level::ERR>(
3101 "ipmiSetSecurityMode: failed to set SpecialMode property",
3102 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3103 return ipmi::responseUnspecifiedError();
3104 }
3105 }
3106#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303107 return ipmi::responseSuccess();
3108}
3109
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003110ipmi::RspType<uint8_t /* restore status */>
3111 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
3112{
3113 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
3114
3115 if (clr != expClr)
3116 {
3117 return ipmi::responseInvalidFieldRequest();
3118 }
3119 constexpr uint8_t cmdStatus = 0;
3120 constexpr uint8_t cmdDefaultRestore = 0xaa;
3121 constexpr uint8_t cmdFullRestore = 0xbb;
3122 constexpr uint8_t cmdFormat = 0xcc;
3123
3124 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3125
3126 switch (cmd)
3127 {
3128 case cmdStatus:
3129 break;
3130 case cmdDefaultRestore:
3131 case cmdFullRestore:
3132 case cmdFormat:
3133 {
3134 // write file to rwfs root
3135 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3136 std::ofstream restoreFile(restoreOpFname);
3137 if (!restoreFile)
3138 {
3139 return ipmi::responseUnspecifiedError();
3140 }
3141 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303142
3143 phosphor::logging::log<phosphor::logging::level::WARNING>(
3144 "Restore to default will be performed on next BMC boot",
3145 phosphor::logging::entry("ACTION=0x%0X", cmd));
3146
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003147 break;
3148 }
3149 default:
3150 return ipmi::responseInvalidFieldRequest();
3151 }
3152
3153 constexpr uint8_t restorePending = 0;
3154 constexpr uint8_t restoreComplete = 1;
3155
3156 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3157 ? restorePending
3158 : restoreComplete;
3159 return ipmi::responseSuccess(restoreStatus);
3160}
3161
Chen Yugang39736d52019-07-12 16:24:33 +08003162ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3163{
3164 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003165 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003166
3167 try
3168 {
3169 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04003170 std::string service =
3171 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
3172 Value variant =
3173 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3174 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
Chen Yugang39736d52019-07-12 16:24:33 +08003175
3176 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3177 std::get<std::string>(variant)))
3178 {
3179 case nmi::NMISource::BMCSourceSignal::None:
3180 bmcSource = static_cast<uint8_t>(NmiSource::none);
3181 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003182 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3183 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003184 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003185 case nmi::NMISource::BMCSourceSignal::Watchdog:
3186 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003187 break;
3188 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3189 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3190 break;
3191 case nmi::NMISource::BMCSourceSignal::MemoryError:
3192 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3193 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003194 case nmi::NMISource::BMCSourceSignal::PciBusError:
3195 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003196 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003197 case nmi::NMISource::BMCSourceSignal::PCH:
3198 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003199 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003200 case nmi::NMISource::BMCSourceSignal::Chipset:
3201 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003202 break;
3203 default:
3204 phosphor::logging::log<phosphor::logging::level::ERR>(
3205 "NMI source: invalid property!",
3206 phosphor::logging::entry(
3207 "PROP=%s", std::get<std::string>(variant).c_str()));
3208 return ipmi::responseResponseError();
3209 }
3210 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05003211 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003212 {
3213 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3214 return ipmi::responseResponseError();
3215 }
3216
3217 return ipmi::responseSuccess(bmcSource);
3218}
3219
3220ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3221{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003222 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003223
3224 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3225 nmi::NMISource::BMCSourceSignal::None;
3226
3227 switch (NmiSource(sourceId))
3228 {
3229 case NmiSource::none:
3230 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3231 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003232 case NmiSource::frontPanelButton:
3233 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003234 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003235 case NmiSource::watchdog:
3236 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003237 break;
3238 case NmiSource::chassisCmd:
3239 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3240 break;
3241 case NmiSource::memoryError:
3242 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3243 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003244 case NmiSource::pciBusError:
3245 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003246 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003247 case NmiSource::pch:
3248 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003249 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003250 case NmiSource::chipset:
3251 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003252 break;
3253 default:
3254 phosphor::logging::log<phosphor::logging::level::ERR>(
3255 "NMI source: invalid property!");
3256 return ipmi::responseResponseError();
3257 }
3258
3259 try
3260 {
3261 // keep NMI signal source
3262 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williams1bcced02024-08-16 15:20:24 -04003263 std::string service =
3264 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003265 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3266 oemNmiBmcSourceObjPathProp,
3267 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003268 // set Enabled property to inform NMI source handling
3269 // to trigger a NMI_OUT BSOD.
3270 // if it's triggered by NMI source property changed,
3271 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3272 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3273 {
3274 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3275 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3276 static_cast<bool>(true));
3277 }
Chen Yugang39736d52019-07-12 16:24:33 +08003278 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003279 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003280 {
3281 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3282 return ipmi::responseResponseError();
3283 }
3284
3285 return ipmi::responseSuccess();
3286}
3287
James Feist63efafa2019-07-24 12:39:21 -07003288namespace dimmOffset
3289{
3290constexpr const char* dimmPower = "DimmPower";
3291constexpr const char* staticCltt = "StaticCltt";
3292constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3293constexpr const char* offsetInterface =
3294 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3295constexpr const char* property = "DimmOffset";
3296
3297}; // namespace dimmOffset
3298
Patrick Williams1bcced02024-08-16 15:20:24 -04003299ipmi::RspType<> ipmiOEMSetDimmOffset(
3300 uint8_t type, const std::vector<std::tuple<uint8_t, uint8_t>>& data)
James Feist63efafa2019-07-24 12:39:21 -07003301{
3302 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3303 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3304 {
3305 return ipmi::responseInvalidFieldRequest();
3306 }
3307
3308 if (data.empty())
3309 {
3310 return ipmi::responseInvalidFieldRequest();
3311 }
3312 nlohmann::json json;
3313
3314 std::ifstream jsonStream(dimmOffsetFile);
3315 if (jsonStream.good())
3316 {
3317 json = nlohmann::json::parse(jsonStream, nullptr, false);
3318 if (json.is_discarded())
3319 {
3320 json = nlohmann::json();
3321 }
3322 jsonStream.close();
3323 }
3324
3325 std::string typeName;
3326 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3327 {
3328 typeName = dimmOffset::dimmPower;
3329 }
3330 else
3331 {
3332 typeName = dimmOffset::staticCltt;
3333 }
3334
3335 nlohmann::json& field = json[typeName];
3336
3337 for (const auto& [index, value] : data)
3338 {
3339 field[index] = value;
3340 }
3341
3342 for (nlohmann::json& val : field)
3343 {
3344 if (val == nullptr)
3345 {
3346 val = static_cast<uint8_t>(0);
3347 }
3348 }
3349
3350 std::ofstream output(dimmOffsetFile);
3351 if (!output.good())
3352 {
3353 std::cerr << "Error writing json file\n";
3354 return ipmi::responseResponseError();
3355 }
3356
3357 output << json.dump(4);
3358
3359 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3360 {
3361 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3362
Jason M. Bills0748c692022-09-08 15:34:08 -07003363 ipmi::DbusVariant offsets = field.get<std::vector<uint8_t>>();
James Feist63efafa2019-07-24 12:39:21 -07003364 auto call = bus->new_method_call(
3365 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3366 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3367 try
3368 {
3369 bus->call(call);
3370 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003371 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003372 {
3373 phosphor::logging::log<phosphor::logging::level::ERR>(
3374 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3375 phosphor::logging::entry("ERR=%s", e.what()));
3376 return ipmi::responseResponseError();
3377 }
3378 }
3379
3380 return ipmi::responseSuccess();
3381}
3382
3383ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3384{
James Feist63efafa2019-07-24 12:39:21 -07003385 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3386 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3387 {
3388 return ipmi::responseInvalidFieldRequest();
3389 }
3390
3391 std::ifstream jsonStream(dimmOffsetFile);
3392
3393 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3394 if (json.is_discarded())
3395 {
3396 std::cerr << "File error in " << dimmOffsetFile << "\n";
3397 return ipmi::responseResponseError();
3398 }
3399
3400 std::string typeName;
3401 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3402 {
3403 typeName = dimmOffset::dimmPower;
3404 }
3405 else
3406 {
3407 typeName = dimmOffset::staticCltt;
3408 }
3409
3410 auto it = json.find(typeName);
3411 if (it == json.end())
3412 {
3413 return ipmi::responseInvalidFieldRequest();
3414 }
3415
3416 if (it->size() <= index)
3417 {
3418 return ipmi::responseInvalidFieldRequest();
3419 }
3420
3421 uint8_t resp = it->at(index).get<uint8_t>();
3422 return ipmi::responseSuccess(resp);
3423}
3424
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003425namespace boot_options
3426{
3427
3428using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3429using IpmiValue = uint8_t;
3430constexpr auto ipmiDefault = 0;
3431
3432std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3433 {0x01, Source::Sources::Network},
3434 {0x02, Source::Sources::Disk},
3435 {0x05, Source::Sources::ExternalMedia},
3436 {0x0f, Source::Sources::RemovableMedia},
3437 {ipmiDefault, Source::Sources::Default}};
3438
3439std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003440 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003441
3442std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3443 {Source::Sources::Network, 0x01},
3444 {Source::Sources::Disk, 0x02},
3445 {Source::Sources::ExternalMedia, 0x05},
3446 {Source::Sources::RemovableMedia, 0x0f},
3447 {Source::Sources::Default, ipmiDefault}};
3448
3449std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003450 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003451
3452static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3453static constexpr auto bootSourceIntf =
3454 "xyz.openbmc_project.Control.Boot.Source";
3455static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3456static constexpr auto persistentObjPath =
3457 "/xyz/openbmc_project/control/host0/boot";
3458static constexpr auto oneTimePath =
3459 "/xyz/openbmc_project/control/host0/boot/one_time";
3460static constexpr auto bootSourceProp = "BootSource";
3461static constexpr auto bootModeProp = "BootMode";
3462static constexpr auto oneTimeBootEnableProp = "Enabled";
3463static constexpr auto httpBootMode =
3464 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3465
3466enum class BootOptionParameter : size_t
3467{
3468 setInProgress = 0x0,
3469 bootFlags = 0x5,
3470};
3471static constexpr uint8_t setComplete = 0x0;
3472static constexpr uint8_t setInProgress = 0x1;
3473static uint8_t transferStatus = setComplete;
3474static constexpr uint8_t setParmVersion = 0x01;
3475static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3476static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3477static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3478static constexpr uint8_t httpBoot = 0xd;
3479static constexpr uint8_t bootSourceMask = 0x3c;
3480
3481} // namespace boot_options
3482
3483ipmi::RspType<uint8_t, // version
3484 uint8_t, // param
3485 uint8_t, // data0, dependent on parameter
3486 std::optional<uint8_t> // data1, dependent on parameter
3487 >
Vernon Mauerydcff1502022-09-28 11:12:46 -07003488 ipmiOemGetEfiBootOptions(uint8_t parameter, [[maybe_unused]] uint8_t set,
3489 [[maybe_unused]] uint8_t block)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003490{
3491 using namespace boot_options;
3492 uint8_t bootOption = 0;
3493
3494 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3495 {
3496 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3497 std::nullopt);
3498 }
3499
3500 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3501 {
3502 phosphor::logging::log<phosphor::logging::level::ERR>(
3503 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003504 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003505 }
3506
3507 try
3508 {
3509 auto oneTimeEnabled = false;
3510 // read one time Enabled property
3511 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3512 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3513 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3514 enabledIntf, oneTimeBootEnableProp);
3515 oneTimeEnabled = std::get<bool>(variant);
3516
3517 // get BootSource and BootMode properties
3518 // according to oneTimeEnable
3519 auto bootObjPath = oneTimePath;
3520 if (oneTimeEnabled == false)
3521 {
3522 bootObjPath = persistentObjPath;
3523 }
3524
3525 service = getService(*dbus, bootModeIntf, bootObjPath);
3526 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3527 bootModeProp);
3528
3529 auto bootMode =
3530 Mode::convertModesFromString(std::get<std::string>(variant));
3531
3532 service = getService(*dbus, bootSourceIntf, bootObjPath);
3533 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3534 bootSourceProp);
3535
3536 if (std::get<std::string>(variant) == httpBootMode)
3537 {
3538 bootOption = httpBoot;
3539 }
3540 else
3541 {
3542 auto bootSource = Source::convertSourcesFromString(
3543 std::get<std::string>(variant));
3544 bootOption = sourceDbusToIpmi.at(bootSource);
3545 if (Source::Sources::Default == bootSource)
3546 {
3547 bootOption = modeDbusToIpmi.at(bootMode);
3548 }
3549 }
3550
3551 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3552 : setParmBootFlagsValidPermanent;
3553 bootOption <<= 2; // shift for responseconstexpr
3554 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3555 bootOption);
3556 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003557 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003558 {
3559 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3560 return ipmi::responseResponseError();
3561 }
3562}
3563
3564ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3565 std::optional<uint8_t> bootOption)
3566{
3567 using namespace boot_options;
3568 auto oneTimeEnabled = false;
3569
Mike Jonesbc01d212022-06-16 12:41:33 -07003570 if (bootFlag == 0 && bootParam == 0)
3571 {
3572 phosphor::logging::log<phosphor::logging::level::ERR>(
3573 "Unsupported parameter");
3574 return ipmi::response(ccParameterNotSupported);
3575 }
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003576 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3577 {
3578 if (bootOption)
3579 {
3580 return ipmi::responseReqDataLenInvalid();
3581 }
3582
3583 if (transferStatus == setInProgress)
3584 {
3585 phosphor::logging::log<phosphor::logging::level::ERR>(
3586 "boot option set in progress!");
3587 return ipmi::responseResponseError();
3588 }
3589
3590 transferStatus = bootParam;
3591 return ipmi::responseSuccess();
3592 }
3593
3594 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3595 {
3596 phosphor::logging::log<phosphor::logging::level::ERR>(
3597 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003598 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003599 }
3600
3601 if (!bootOption)
3602 {
3603 return ipmi::responseReqDataLenInvalid();
3604 }
3605
3606 if (((bootOption.value() & bootSourceMask) >> 2) !=
3607 httpBoot) // not http boot, exit
3608 {
3609 phosphor::logging::log<phosphor::logging::level::ERR>(
3610 "wrong boot option parameter!");
3611 return ipmi::responseParmOutOfRange();
3612 }
3613
3614 try
3615 {
3616 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3617 setParmBootFlagsPermanent;
3618
3619 // read one time Enabled property
3620 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3621 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3622 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3623 enabledIntf, oneTimeBootEnableProp);
3624 oneTimeEnabled = std::get<bool>(variant);
3625
3626 /*
3627 * Check if the current boot setting is onetime or permanent, if the
3628 * request in the command is otherwise, then set the "Enabled"
3629 * property in one_time object path to 'True' to indicate onetime
3630 * and 'False' to indicate permanent.
3631 *
3632 * Once the onetime/permanent setting is applied, then the bootMode
3633 * and bootSource is updated for the corresponding object.
3634 */
3635 if (permanent == oneTimeEnabled)
3636 {
3637 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3638 oneTimeBootEnableProp, !permanent);
3639 }
3640
3641 // set BootSource and BootMode properties
3642 // according to oneTimeEnable or persistent
3643 auto bootObjPath = oneTimePath;
3644 if (oneTimeEnabled == false)
3645 {
3646 bootObjPath = persistentObjPath;
3647 }
3648 std::string bootMode =
3649 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3650 std::string bootSource = httpBootMode;
3651
3652 service = getService(*dbus, bootModeIntf, bootObjPath);
3653 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3654 bootMode);
3655
3656 service = getService(*dbus, bootSourceIntf, bootObjPath);
3657 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3658 bootSourceProp, bootSource);
3659 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003660 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003661 {
3662 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3663 return ipmi::responseResponseError();
3664 }
3665
3666 return ipmi::responseSuccess();
3667}
3668
Jason M. Bills0748c692022-09-08 15:34:08 -07003669using BasicVariantType = ipmi::DbusVariant;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003670using PropertyMapType =
3671 boost::container::flat_map<std::string, BasicVariantType>;
3672static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3673 "xyz.openbmc_project.Configuration.PSUPresence"};
Vernon Mauerydcff1502022-09-28 11:12:46 -07003674int getPSUAddress(ipmi::Context::ptr& ctx, uint8_t& bus,
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003675 std::vector<uint64_t>& addrTable)
3676{
3677 boost::system::error_code ec;
3678 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3679 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3680 "/xyz/openbmc_project/object_mapper",
3681 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3682 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3683 if (ec)
3684 {
3685 phosphor::logging::log<phosphor::logging::level::ERR>(
3686 "Failed to set dbus property to cold redundancy");
3687 return -1;
3688 }
3689 for (const auto& object : subtree)
3690 {
3691 std::string pathName = object.first;
3692 for (const auto& serviceIface : object.second)
3693 {
3694 std::string serviceName = serviceIface.first;
3695
3696 ec.clear();
3697 PropertyMapType propMap =
3698 ctx->bus->yield_method_call<PropertyMapType>(
3699 ctx->yield, ec, serviceName, pathName,
3700 "org.freedesktop.DBus.Properties", "GetAll",
3701 "xyz.openbmc_project.Configuration.PSUPresence");
3702 if (ec)
3703 {
3704 phosphor::logging::log<phosphor::logging::level::ERR>(
3705 "Failed to set dbus property to cold redundancy");
3706 return -1;
3707 }
3708 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3709 auto psuAddress =
3710 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3711
3712 if (psuBus == nullptr || psuAddress == nullptr)
3713 {
3714 std::cerr << "error finding necessary "
3715 "entry in configuration\n";
3716 return -1;
3717 }
3718 bus = static_cast<uint8_t>(*psuBus);
3719 addrTable = *psuAddress;
3720 return 0;
3721 }
3722 }
3723 return -1;
3724}
3725
3726static const constexpr uint8_t addrOffset = 8;
3727static const constexpr uint8_t psuRevision = 0xd9;
3728static const constexpr uint8_t defaultPSUBus = 7;
3729// Second Minor, Primary Minor, Major
3730static const constexpr size_t verLen = 3;
Vernon Mauerydcff1502022-09-28 11:12:46 -07003731ipmi::RspType<std::vector<uint8_t>>
3732 ipmiOEMGetPSUVersion(ipmi::Context::ptr& ctx)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003733{
3734 uint8_t bus = defaultPSUBus;
3735 std::vector<uint64_t> addrTable;
3736 std::vector<uint8_t> result;
3737 if (getPSUAddress(ctx, bus, addrTable))
3738 {
3739 std::cerr << "Failed to get PSU bus and address\n";
3740 return ipmi::responseResponseError();
3741 }
3742
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003743 for (const auto& targetAddr : addrTable)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003744 {
3745 std::vector<uint8_t> writeData = {psuRevision};
3746 std::vector<uint8_t> readBuf(verLen);
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003747 uint8_t addr = static_cast<uint8_t>(targetAddr) + addrOffset;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003748 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3749
3750 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3751 if (retI2C != ipmi::ccSuccess)
3752 {
3753 for (size_t idx = 0; idx < verLen; idx++)
3754 {
3755 result.emplace_back(0x00);
3756 }
3757 }
3758 else
3759 {
3760 for (const uint8_t& data : readBuf)
3761 {
3762 result.emplace_back(data);
3763 }
3764 }
3765 }
3766
3767 return ipmi::responseSuccess(result);
3768}
3769
Patrick Williams1bcced02024-08-16 15:20:24 -04003770std::optional<uint8_t>
3771 getMultiNodeInfoPresence(ipmi::Context::ptr& ctx, const std::string& name)
srikanta mondal2030d7c2020-05-03 17:25:25 +00003772{
3773 Value dbusValue = 0;
3774 std::string serviceName;
3775
3776 boost::system::error_code ec =
3777 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3778
3779 if (ec)
3780 {
3781 phosphor::logging::log<phosphor::logging::level::ERR>(
3782 "Failed to perform Multinode getService.");
3783 return std::nullopt;
3784 }
3785
3786 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3787 multiNodeIntf, name, dbusValue);
3788 if (ec)
3789 {
3790 phosphor::logging::log<phosphor::logging::level::ERR>(
3791 "Failed to perform Multinode get property");
3792 return std::nullopt;
3793 }
3794
3795 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3796 if (!multiNodeVal)
3797 {
3798 phosphor::logging::log<phosphor::logging::level::ERR>(
3799 "getMultiNodeInfoPresence: error to get multinode");
3800 return std::nullopt;
3801 }
3802 return *multiNodeVal;
3803}
3804
3805/** @brief implements OEM get reading command
3806 * @param domain ID
3807 * @param reading Type
3808 * - 00h = platform Power Consumption
3809 * - 01h = inlet Air Temp
3810 * - 02h = icc_TDC from PECI
3811 * @param reserved, write as 0000h
3812 *
3813 * @returns IPMI completion code plus response data
3814 * - response
3815 * - domain ID
3816 * - reading Type
3817 * - 00h = platform Power Consumption
3818 * - 01h = inlet Air Temp
3819 * - 02h = icc_TDC from PECI
3820 * - reading
3821 */
3822ipmi::RspType<uint4_t, // domain ID
3823 uint4_t, // reading Type
3824 uint16_t // reading Value
3825 >
Vernon Mauerydcff1502022-09-28 11:12:46 -07003826 ipmiOEMGetReading(ipmi::Context::ptr& ctx, uint4_t domainId,
srikanta mondal2030d7c2020-05-03 17:25:25 +00003827 uint4_t readingType, uint16_t reserved)
3828{
Vernon Mauerydcff1502022-09-28 11:12:46 -07003829 [[maybe_unused]] constexpr uint8_t platformPower = 0;
srikanta mondal2030d7c2020-05-03 17:25:25 +00003830 constexpr uint8_t inletAirTemp = 1;
3831 constexpr uint8_t iccTdc = 2;
3832
3833 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3834 {
3835 return ipmi::responseInvalidFieldRequest();
3836 }
3837
3838 // This command should run only from multi-node product.
3839 // For all other platforms this command will return invalid.
3840
Patrick Williams1bcced02024-08-16 15:20:24 -04003841 std::optional<uint8_t> nodeInfo =
3842 getMultiNodeInfoPresence(ctx, "NodePresence");
srikanta mondal2030d7c2020-05-03 17:25:25 +00003843 if (!nodeInfo || !*nodeInfo)
3844 {
3845 return ipmi::responseInvalidCommand();
3846 }
3847
3848 uint16_t oemReadingValue = 0;
3849 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3850 {
3851 double value = 0;
3852 boost::system::error_code ec = ipmi::getDbusProperty(
3853 ctx, "xyz.openbmc_project.HwmonTempSensor",
3854 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3855 "xyz.openbmc_project.Sensor.Value", "Value", value);
3856 if (ec)
3857 {
3858 phosphor::logging::log<phosphor::logging::level::ERR>(
3859 "Failed to get BMC Get OEM temperature",
3860 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3861 return ipmi::responseUnspecifiedError();
3862 }
3863 // Take the Inlet temperature
3864 oemReadingValue = static_cast<uint16_t>(value);
3865 }
3866 else
3867 {
3868 phosphor::logging::log<phosphor::logging::level::ERR>(
3869 "Currently Get OEM Reading support only for Inlet Air Temp");
3870 return ipmi::responseParmOutOfRange();
3871 }
3872 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3873}
3874
AppaRao Puli28972062019-11-11 02:04:45 +05303875/** @brief implements the maximum size of
3876 * bridgeable messages used between KCS and
3877 * IPMB interfacesget security mode command.
3878 *
3879 * @returns IPMI completion code with following data
3880 * - KCS Buffer Size (In multiples of four bytes)
3881 * - IPMB Buffer Size (In multiples of four bytes)
3882 **/
3883ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3884{
3885 // for now this is hard coded; really this number is dependent on
3886 // the BMC kcs driver as well as the host kcs driver....
3887 // we can't know the latter.
3888 uint8_t kcsMaxBufferSize = 63 / 4;
3889 uint8_t ipmbMaxBufferSize = 128 / 4;
3890
3891 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3892}
3893
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003894ipmi::RspType<std::vector<uint8_t>>
3895 ipmiOEMReadPFRMailbox(ipmi::Context::ptr& ctx, const uint8_t readRegister,
3896 const uint8_t numOfBytes, uint8_t registerIdentifier)
3897{
3898 if (!ipmi::mailbox::i2cConfigLoaded)
3899 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003900 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003901 "Calling PFR Load Configuration Function to Get I2C Bus and Target "
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003902 "Address ");
3903
3904 ipmi::mailbox::loadPfrConfig(ctx, ipmi::mailbox::i2cConfigLoaded);
3905 }
3906
3907 if (!numOfBytes && !readRegister)
3908 {
3909 phosphor::logging::log<phosphor::logging::level::ERR>(
3910 "OEM IPMI command: Read & write count are 0 which is invalid ");
3911 return ipmi::responseInvalidFieldRequest();
3912 }
3913
3914 switch (registerIdentifier)
3915 {
3916 case ipmi::mailbox::registerType::fifoReadRegister:
3917 {
3918 // Check if readRegister is an FIFO read register
Vernon Mauerydcff1502022-09-28 11:12:46 -07003919 if (ipmi::mailbox::readFifoReg.find(readRegister) ==
3920 ipmi::mailbox::readFifoReg.end())
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003921 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003922 phosphor::logging::log<phosphor::logging::level::ERR>(
Vernon Mauerydcff1502022-09-28 11:12:46 -07003923 "OEM IPMI command: Register is not a Read FIFO ");
3924 return ipmi::responseInvalidFieldRequest();
3925 }
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003926
Vernon Mauerydcff1502022-09-28 11:12:46 -07003927 phosphor::logging::log<phosphor::logging::level::ERR>(
3928 "OEM IPMI command: Register is a Read FIFO ");
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003929
Vernon Mauerydcff1502022-09-28 11:12:46 -07003930 ipmi::mailbox::writefifo(ipmi::mailbox::provisioningCommand,
3931 readRegister);
3932 ipmi::mailbox::writefifo(ipmi::mailbox::triggerCommand,
3933 ipmi::mailbox::flushRead);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003934
Vernon Mauerydcff1502022-09-28 11:12:46 -07003935 std::vector<uint8_t> writeData = {ipmi::mailbox::readFifo};
3936 std::vector<uint8_t> readBuf(1);
3937 std::vector<uint8_t> result;
3938
3939 for (int i = 0; i < numOfBytes; i++)
3940 {
3941 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
3942 ipmi::mailbox::targetAddr,
3943 writeData, readBuf);
3944 if (ret != ipmi::ccSuccess)
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003945 {
Vernon Mauerydcff1502022-09-28 11:12:46 -07003946 return ipmi::response(ret);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003947 }
3948
Vernon Mauerydcff1502022-09-28 11:12:46 -07003949 else
3950 {
3951 for (const uint8_t& data : readBuf)
3952 {
3953 result.emplace_back(data);
3954 }
3955 }
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003956 }
Vernon Mauerydcff1502022-09-28 11:12:46 -07003957
3958 return ipmi::responseSuccess(result);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003959 }
3960
3961 case ipmi::mailbox::registerType::singleByteRegister:
3962 {
3963 phosphor::logging::log<phosphor::logging::level::ERR>(
3964 "OEM IPMI command: Register is a Single Byte Register ");
3965
3966 std::vector<uint8_t> writeData = {readRegister};
3967 std::vector<uint8_t> readBuf(numOfBytes);
3968
3969 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003970 ipmi::mailbox::targetAddr,
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003971 writeData, readBuf);
3972 if (ret != ipmi::ccSuccess)
3973 {
3974 return ipmi::response(ret);
3975 }
3976 return ipmi::responseSuccess(readBuf);
3977 }
3978
3979 default:
3980 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003981 phosphor::logging::log<phosphor::logging::level::ERR>(
3982 "OEM IPMI command: Register identifier is not valid.It should "
3983 "be 0 "
3984 "for Single Byte Register and 1 for FIFO Read Register");
3985
3986 return ipmi::responseInvalidFieldRequest();
3987 }
3988 }
3989}
3990
Jason M. Bills64796042018-10-03 16:51:55 -07003991static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003992{
3993 phosphor::logging::log<phosphor::logging::level::INFO>(
3994 "Registering OEM commands");
Vernon Maueryaf652682023-08-04 13:37:21 -07003995 registerHandler(prioOemBase, intel::netFnGeneral,
3996 intel::general::cmdGetBmcVersionString, Privilege::User,
3997 ipmiOEMGetBmcVersionString);
3998
Vernon Mauery98bbf692019-09-16 11:14:59 -07003999 ipmiPrintAndRegister(intel::netFnGeneral,
4000 intel::general::cmdGetChassisIdentifier, NULL,
4001 ipmiOEMGetChassisIdentifier,
4002 PRIVILEGE_USER); // get chassis identifier
4003
4004 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
4005 NULL, ipmiOEMSetSystemGUID,
4006 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07004007
4008 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004009 registerHandler(prioOemBase, intel::netFnGeneral,
4010 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
4011 ipmiOEMDisableBMCSystemReset);
4012
Jason M. Billsb02bf092019-08-15 13:01:56 -07004013 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004014 registerHandler(prioOemBase, intel::netFnGeneral,
4015 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
4016 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07004017
Vernon Mauery98bbf692019-09-16 11:14:59 -07004018 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
4019 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004020
Chen Yugang7a04f3a2019-10-08 11:12:35 +08004021 registerHandler(prioOemBase, intel::netFnGeneral,
4022 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
4023 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004024
Vernon Mauery98bbf692019-09-16 11:14:59 -07004025 ipmiPrintAndRegister(intel::netFnGeneral,
4026 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
4027 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304028
Vernon Mauery98bbf692019-09-16 11:14:59 -07004029 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4030 intel::general::cmdSendEmbeddedFWUpdStatus,
4031 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304032
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05304033 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
4034 Privilege::Admin, ipmiOEMSlotIpmb);
4035
Vernon Mauery98bbf692019-09-16 11:14:59 -07004036 ipmiPrintAndRegister(intel::netFnGeneral,
4037 intel::general::cmdSetPowerRestoreDelay, NULL,
4038 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
4039
4040 ipmiPrintAndRegister(intel::netFnGeneral,
4041 intel::general::cmdGetPowerRestoreDelay, NULL,
4042 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
4043
4044 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4045 intel::general::cmdSetOEMUser2Activation,
4046 Privilege::Callback, ipmiOEMSetUser2Activation);
4047
4048 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4049 intel::general::cmdSetSpecialUserPassword,
4050 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05304051
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004052 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004053 registerHandler(prioOemBase, intel::netFnGeneral,
4054 intel::general::cmdGetProcessorErrConfig, Privilege::User,
4055 ipmiOEMGetProcessorErrConfig);
4056
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004057 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004058 registerHandler(prioOemBase, intel::netFnGeneral,
4059 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
4060 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004061
Vernon Mauery98bbf692019-09-16 11:14:59 -07004062 ipmiPrintAndRegister(intel::netFnGeneral,
4063 intel::general::cmdSetShutdownPolicy, NULL,
4064 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004065
Vernon Mauery98bbf692019-09-16 11:14:59 -07004066 ipmiPrintAndRegister(intel::netFnGeneral,
4067 intel::general::cmdGetShutdownPolicy, NULL,
4068 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004069
anil kumar appanaf945eee2019-09-25 23:29:11 +00004070 registerHandler(prioOemBase, intel::netFnGeneral,
4071 intel::general::cmdSetFanConfig, Privilege::User,
4072 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08004073
Vernon Mauery98bbf692019-09-16 11:14:59 -07004074 registerHandler(prioOemBase, intel::netFnGeneral,
4075 intel::general::cmdGetFanConfig, Privilege::User,
4076 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07004077
Vernon Mauery98bbf692019-09-16 11:14:59 -07004078 registerHandler(prioOemBase, intel::netFnGeneral,
4079 intel::general::cmdGetFanSpeedOffset, Privilege::User,
4080 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004081
Vernon Mauery98bbf692019-09-16 11:14:59 -07004082 registerHandler(prioOemBase, intel::netFnGeneral,
4083 intel::general::cmdSetFanSpeedOffset, Privilege::User,
4084 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004085
Vernon Mauery98bbf692019-09-16 11:14:59 -07004086 registerHandler(prioOemBase, intel::netFnGeneral,
4087 intel::general::cmdSetFscParameter, Privilege::User,
4088 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07004089
Vernon Mauery98bbf692019-09-16 11:14:59 -07004090 registerHandler(prioOemBase, intel::netFnGeneral,
4091 intel::general::cmdGetFscParameter, Privilege::User,
4092 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05304093
Vernon Mauery98bbf692019-09-16 11:14:59 -07004094 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4095 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
4096 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08004097
Vernon Mauery98bbf692019-09-16 11:14:59 -07004098 registerHandler(prioOemBase, intel::netFnGeneral,
4099 intel::general::cmdGetNmiStatus, Privilege::User,
4100 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08004101
Vernon Mauery98bbf692019-09-16 11:14:59 -07004102 registerHandler(prioOemBase, intel::netFnGeneral,
4103 intel::general::cmdSetNmiStatus, Privilege::Operator,
4104 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004105
Vernon Mauery98bbf692019-09-16 11:14:59 -07004106 registerHandler(prioOemBase, intel::netFnGeneral,
4107 intel::general::cmdGetEfiBootOptions, Privilege::User,
4108 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004109
Vernon Mauery98bbf692019-09-16 11:14:59 -07004110 registerHandler(prioOemBase, intel::netFnGeneral,
4111 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
4112 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304113
Vernon Mauery98bbf692019-09-16 11:14:59 -07004114 registerHandler(prioOemBase, intel::netFnGeneral,
4115 intel::general::cmdGetSecurityMode, Privilege::User,
4116 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304117
Vernon Mauery98bbf692019-09-16 11:14:59 -07004118 registerHandler(prioOemBase, intel::netFnGeneral,
4119 intel::general::cmdSetSecurityMode, Privilege::Admin,
4120 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004121
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00004122 registerHandler(prioOemBase, intel::netFnGeneral,
4123 intel::general::cmdGetLEDStatus, Privilege::Admin,
4124 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08004125
Vernon Mauery98bbf692019-09-16 11:14:59 -07004126 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
4127 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
4128 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
4129
4130 registerHandler(prioOemBase, intel::netFnGeneral,
4131 intel::general::cmdSetFaultIndication, Privilege::Operator,
4132 ipmiOEMSetFaultIndication);
4133
4134 registerHandler(prioOemBase, intel::netFnGeneral,
4135 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
4136 ipmiOEMSetCRConfig);
4137
4138 registerHandler(prioOemBase, intel::netFnGeneral,
4139 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
4140 ipmiOEMGetCRConfig);
4141
4142 registerHandler(prioOemBase, intel::netFnGeneral,
4143 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004144 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07004145
Vernon Mauery98bbf692019-09-16 11:14:59 -07004146 registerHandler(prioOemBase, intel::netFnGeneral,
4147 intel::general::cmdSetDimmOffset, Privilege::Operator,
4148 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07004149
Vernon Mauery98bbf692019-09-16 11:14:59 -07004150 registerHandler(prioOemBase, intel::netFnGeneral,
4151 intel::general::cmdGetDimmOffset, Privilege::Operator,
4152 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08004153
Cheng C Yang4e6ee152019-09-25 10:27:44 +08004154 registerHandler(prioOemBase, intel::netFnGeneral,
4155 intel::general::cmdGetPSUVersion, Privilege::User,
4156 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05304157
4158 registerHandler(prioOemBase, intel::netFnGeneral,
4159 intel::general::cmdGetBufferSize, Privilege::User,
4160 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00004161
4162 registerHandler(prioOemBase, intel::netFnGeneral,
4163 intel::general::cmdOEMGetReading, Privilege::User,
4164 ipmiOEMGetReading);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00004165
4166 registerHandler(prioOemBase, intel::netFnApp, intel::app::cmdPFRMailboxRead,
4167 Privilege::Admin, ipmiOEMReadPFRMailbox);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004168}
4169
4170} // namespace ipmi