blob: d0158de8e8b2c7b750ebdc738de70163bd5aedc7 [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 Williamsb37abfb2023-05-10 07:50:33 -0500271 ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, targetAddr, writeData,
272 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
Jason M. Billsb02bf092019-08-15 13:01:56 -0700377ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
378 uint7_t reserved1)
379{
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 Williamsb37abfb2023-05-10 07:50:33 -0500389 auto service = ipmi::getService(*busp, bmcResetDisablesIntf,
390 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 Williamsb37abfb2023-05-10 07:50:33 -0500416 auto service = ipmi::getService(*busp, bmcResetDisablesIntf,
417 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 Williamsb37abfb2023-05-10 07:50:33 -0500472 std::string hsbpObjPath = "/xyz/openbmc_project/software/HSBP_" +
473 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]));
Jayaprakash Mutyalad0657022021-08-26 21:18:08 +0000563 meMinor = static_cast<uint8_t>(std::stoi(results[2]) << 4 |
564 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 Williamsb37abfb2023-05-10 07:50:33 -0500597 std::string service = getService(*dbus, biosVersionIntf,
598 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 Williamsb37abfb2023-05-10 07:50:33 -0500720 std::string service = getService(*dbus, powerRestoreDelayIntf,
721 powerRestoreDelayObjPath);
722 Value variant = getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
723 powerRestoreDelayIntf,
724 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.
745ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
746 uint8_t majorRevision,
747 uint8_t minorRevision,
748 uint32_t auxInfo)
749{
750 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700751 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800752 target = (target & selEvtTargetMask) >> selEvtTargetShift;
753
754 /* make sure the status is 0, 1, or 2 as per the spec */
755 if (status > 2)
756 {
757 return ipmi::response(ipmi::ccInvalidFieldRequest);
758 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700759 /* make sure the target is 0, 1, 2, or 4 as per the spec */
760 if (target > 4 || target == 3)
761 {
762 return ipmi::response(ipmi::ccInvalidFieldRequest);
763 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800764 /*orignal OEM command is to record OEM SEL.
765 But openbmc does not support OEM SEL, so we redirect it to redfish event
766 logging. */
767 std::string buildInfo;
768 std::string action;
769 switch (FWUpdateTarget(target))
770 {
771 case FWUpdateTarget::targetBMC:
772 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700773 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800774 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
775 " BuildID: " + std::to_string(auxInfo);
776 buildInfo += std::to_string(auxInfo);
777 break;
778 case FWUpdateTarget::targetBIOS:
779 firmware = "BIOS";
780 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700781 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800782 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
783 " minor: " +
784 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
785 " ReleaseNumber: " + // ASCII encoded
786 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
787 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
788 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
789 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
790 break;
791 case FWUpdateTarget::targetME:
792 firmware = "ME";
793 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700794 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800795 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
796 " minor2: " +
797 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
798 " build1: " +
799 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
800 " build2: " +
801 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
802 break;
803 case FWUpdateTarget::targetOEMEWS:
804 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700805 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800806 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
807 " BuildID: " + std::to_string(auxInfo);
808 break;
809 }
810
Jason M. Billsdc249272019-04-03 09:58:40 -0700811 static const std::string openBMCMessageRegistryVersion("0.1");
812 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
813
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800814 switch (status)
815 {
816 case 0x0:
817 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700818 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800819 break;
820 case 0x1:
821 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700822 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800823 break;
824 case 0x2:
825 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700826 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800827 break;
828 default:
829 action = "unknown";
830 break;
831 }
832
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500833 std::string firmwareInstanceStr = firmware +
834 " instance: " + std::to_string(instance);
Jason M. Billsdc249272019-04-03 09:58:40 -0700835 std::string message("[firmware update] " + firmwareInstanceStr +
836 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800837
838 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700839 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
840 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
841 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800842 return ipmi::responseSuccess();
843}
844
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530845ipmi::RspType<uint8_t, std::vector<uint8_t>>
Vernon Mauerydcff1502022-09-28 11:12:46 -0700846 ipmiOEMSlotIpmb(ipmi::Context::ptr& ctx, uint6_t reserved1,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530847 uint2_t slotNumber, uint3_t baseBoardSlotNum,
Vernon Mauerydcff1502022-09-28 11:12:46 -0700848 [[maybe_unused]] uint3_t riserSlotNum, uint2_t reserved2,
849 uint8_t targetAddr, uint8_t netFn, uint8_t cmd,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530850 std::optional<std::vector<uint8_t>> writeData)
851{
852 if (reserved1 || reserved2)
853 {
854 return ipmi::responseInvalidFieldRequest();
855 }
856
857 boost::system::error_code ec;
858 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
859 std::vector<uint8_t>>;
860 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
861 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
862 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
863 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800864 static_cast<uint8_t>(baseBoardSlotNum), targetAddr, netFn, cmd,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530865 *writeData);
866 if (ec)
867 {
868 phosphor::logging::log<phosphor::logging::level::ERR>(
869 "Failed to call dbus method SlotIpmbRequest");
870 return ipmi::responseUnspecifiedError();
871 }
872
873 std::vector<uint8_t> dataReceived(0);
874 int status = -1;
875 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
876
877 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
878
879 if (status)
880 {
881 phosphor::logging::log<phosphor::logging::level::ERR>(
882 "Failed to get response from SlotIpmbRequest");
883 return ipmi::responseResponseError();
884 }
885 return ipmi::responseSuccess(cc, dataReceived);
886}
887
Vernon Mauerydcff1502022-09-28 11:12:46 -0700888ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t, ipmi_cmd_t,
889 ipmi_request_t request, ipmi_response_t,
890 ipmi_data_len_t dataLen, ipmi_context_t)
Jason M. Bills64796042018-10-03 16:51:55 -0700891{
892 SetPowerRestoreDelayReq* data =
893 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
894 uint16_t delay = 0;
895
896 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
897 {
898 *dataLen = 0;
899 return IPMI_CC_REQ_DATA_LEN_INVALID;
900 }
901 delay = data->byteMSB;
902 delay = (delay << 8) | data->byteLSB;
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300903 uint64_t val = delay * 1000000;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700904 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500905 std::string service = getService(*dbus, powerRestoreDelayIntf,
906 powerRestoreDelayObjPath);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700907 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300908 powerRestoreDelayIntf, powerRestoreDelayProp, val);
Jason M. Bills64796042018-10-03 16:51:55 -0700909 *dataLen = 0;
910
911 return IPMI_CC_OK;
912}
913
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700914static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700915{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700916 static constexpr const char* cpuPresencePathPrefix =
917 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
918 static constexpr const char* cpuPresenceIntf =
919 "xyz.openbmc_project.Inventory.Item";
920 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
921 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
922 try
Jason M. Bills64796042018-10-03 16:51:55 -0700923 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500924 auto service = ipmi::getService(*busp, cpuPresenceIntf,
925 cpuPresencePath);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700926
927 ipmi::Value result = ipmi::getDbusProperty(
928 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
929 return std::get<bool>(result);
930 }
931 catch (const std::exception& e)
932 {
933 phosphor::logging::log<phosphor::logging::level::INFO>(
934 "Cannot find processor presence",
935 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
936 return false;
937 }
938}
939
Jason M. Billsf284f852023-09-07 15:48:48 -0700940ipmi::RspType<bool, // IERR Reset Enabled
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700941 bool, // ERR2 Reset Enabled
Jason M. Bills51cf3112023-09-07 15:50:23 -0700942 bool, // MCERR Reset Enabled
943 uint5_t, // reserved
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700944 uint8_t, // reserved, returns 0x3F
Jason M. Billsf284f852023-09-07 15:48:48 -0700945 uint6_t, // CPU1 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700946 uint2_t, // CPU1 Status
Jason M. Billsf284f852023-09-07 15:48:48 -0700947 uint6_t, // CPU2 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700948 uint2_t, // CPU2 Status
Jason M. Billsf284f852023-09-07 15:48:48 -0700949 uint6_t, // CPU3 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700950 uint2_t, // CPU3 Status
Jason M. Billsf284f852023-09-07 15:48:48 -0700951 uint6_t, // CPU4 IERR Count
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700952 uint2_t, // CPU4 Status
953 uint8_t // Crashdump Count
954 >
955 ipmiOEMGetProcessorErrConfig()
956{
Jason M. Billsf284f852023-09-07 15:48:48 -0700957 bool resetOnIERR = false;
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700958 bool resetOnERR2 = false;
Jason M. Bills51cf3112023-09-07 15:50:23 -0700959 bool allowResetOnMCERR = false;
Jason M. Billsf284f852023-09-07 15:48:48 -0700960 uint6_t cpu1IERRCount = 0;
961 uint6_t cpu2IERRCount = 0;
962 uint6_t cpu3IERRCount = 0;
963 uint6_t cpu4IERRCount = 0;
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700964 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700965 uint2_t cpu1Status = cpuPresent("CPU_1")
966 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
967 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
968 uint2_t cpu2Status = cpuPresent("CPU_2")
969 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
970 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
971 uint2_t cpu3Status = cpuPresent("CPU_3")
972 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
973 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
974 uint2_t cpu4Status = cpuPresent("CPU_4")
975 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
976 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700977
978 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
979 try
980 {
981 auto service = ipmi::getService(*busp, processorErrConfigIntf,
982 processorErrConfigObjPath);
983
984 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
985 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
Jason M. Billsf284f852023-09-07 15:48:48 -0700986 resetOnIERR = std::get<bool>(result.at("ResetOnIERR"));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700987 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
Jason M. Bills51cf3112023-09-07 15:50:23 -0700988 allowResetOnMCERR = std::get<bool>(result.at("AllowResetOnMCERR"));
Jason M. Billsf284f852023-09-07 15:48:48 -0700989 cpu1IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
990 cpu2IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
991 cpu3IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
992 cpu4IERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700993 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
994 }
995 catch (const std::exception& e)
996 {
997 phosphor::logging::log<phosphor::logging::level::ERR>(
998 "Failed to fetch processor error config",
999 phosphor::logging::entry("ERROR=%s", e.what()));
1000 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -07001001 }
1002
Jason M. Bills51cf3112023-09-07 15:50:23 -07001003 return ipmi::responseSuccess(resetOnIERR, resetOnERR2, allowResetOnMCERR, 0,
1004 0x3F, cpu1IERRCount, cpu1Status, cpu2IERRCount,
Jason M. Billsf284f852023-09-07 15:48:48 -07001005 cpu2Status, cpu3IERRCount, cpu3Status,
1006 cpu4IERRCount, cpu4Status, crashdumpCount);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001007}
Jason M. Bills64796042018-10-03 16:51:55 -07001008
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001009ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
Jason M. Bills51cf3112023-09-07 15:50:23 -07001010 bool resetOnIERR, bool resetOnERR2, bool allowResetOnMCERR,
1011 uint5_t reserved1, uint8_t reserved2,
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001012 std::optional<bool> clearCPUErrorCount,
1013 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
1014{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +00001015 if (reserved1 || reserved2)
1016 {
1017 return ipmi::responseInvalidFieldRequest();
1018 }
1019
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001020 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -07001021
1022 try
1023 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +00001024 if (reserved3.value_or(0))
1025 {
1026 return ipmi::responseInvalidFieldRequest();
1027 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001028 auto service = ipmi::getService(*busp, processorErrConfigIntf,
1029 processorErrConfigObjPath);
1030 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsf284f852023-09-07 15:48:48 -07001031 processorErrConfigIntf, "ResetOnIERR",
1032 resetOnIERR);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001033 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1034 processorErrConfigIntf, "ResetOnERR2",
1035 resetOnERR2);
Jason M. Bills51cf3112023-09-07 15:50:23 -07001036 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1037 processorErrConfigIntf, "AllowResetOnMCERR",
1038 allowResetOnMCERR);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001039 if (clearCPUErrorCount.value_or(false))
1040 {
1041 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001042 processorErrConfigIntf, "ErrorCountCPU1",
1043 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001044 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001045 processorErrConfigIntf, "ErrorCountCPU2",
1046 static_cast<uint8_t>(0));
1047 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1048 processorErrConfigIntf, "ErrorCountCPU3",
1049 static_cast<uint8_t>(0));
1050 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1051 processorErrConfigIntf, "ErrorCountCPU4",
1052 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001053 }
1054 if (clearCrashdumpCount.value_or(false))
1055 {
1056 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001057 processorErrConfigIntf, "CrashdumpCount",
1058 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001059 }
Jason M. Bills64796042018-10-03 16:51:55 -07001060 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001061 catch (const std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -07001062 {
Kuiying Wangbc546672018-11-23 15:41:05 +08001063 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001064 "Failed to set processor error config",
1065 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1066 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -07001067 }
1068
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001069 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -07001070}
1071
Vernon Mauerydcff1502022-09-28 11:12:46 -07001072ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t, ipmi_cmd_t, ipmi_request_t,
Yong Li703922d2018-11-06 13:25:31 +08001073 ipmi_response_t response,
Vernon Mauerydcff1502022-09-28 11:12:46 -07001074 ipmi_data_len_t dataLen, ipmi_context_t)
Yong Li703922d2018-11-06 13:25:31 +08001075{
1076 GetOEMShutdownPolicyRes* resp =
1077 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
1078
1079 if (*dataLen != 0)
1080 {
1081 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +08001082 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +08001083 *dataLen = 0;
1084 return IPMI_CC_REQ_DATA_LEN_INVALID;
1085 }
1086
1087 *dataLen = 0;
1088
1089 try
1090 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001091 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001092 std::string service = getService(*dbus, oemShutdownPolicyIntf,
1093 oemShutdownPolicyObjPath);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001094 Value variant = getDbusProperty(
1095 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
1096 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +08001097
1098 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1099 convertPolicyFromString(std::get<std::string>(variant)) ==
1100 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1101 NoShutdownOnOCOT)
1102 {
1103 resp->policy = 0;
1104 }
1105 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1106 convertPolicyFromString(std::get<std::string>(variant)) ==
1107 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1108 Policy::ShutdownOnOCOT)
1109 {
1110 resp->policy = 1;
1111 }
1112 else
1113 {
1114 phosphor::logging::log<phosphor::logging::level::ERR>(
1115 "oem_set_shutdown_policy: invalid property!",
1116 phosphor::logging::entry(
1117 "PROP=%s", std::get<std::string>(variant).c_str()));
1118 return IPMI_CC_UNSPECIFIED_ERROR;
1119 }
Yong Li703922d2018-11-06 13:25:31 +08001120 // TODO needs to check if it is multi-node products,
1121 // policy is only supported on node 3/4
1122 resp->policySupport = shutdownPolicySupported;
1123 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001124 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001125 {
1126 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1127 return IPMI_CC_UNSPECIFIED_ERROR;
1128 }
1129
1130 *dataLen = sizeof(GetOEMShutdownPolicyRes);
1131 return IPMI_CC_OK;
1132}
1133
Vernon Mauerydcff1502022-09-28 11:12:46 -07001134ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t, ipmi_cmd_t,
1135 ipmi_request_t request, ipmi_response_t,
1136 ipmi_data_len_t dataLen, ipmi_context_t)
Yong Li703922d2018-11-06 13:25:31 +08001137{
1138 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +08001139 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
1140 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1141 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +08001142
1143 // TODO needs to check if it is multi-node products,
1144 // policy is only supported on node 3/4
1145 if (*dataLen != 1)
1146 {
1147 phosphor::logging::log<phosphor::logging::level::ERR>(
1148 "oem_set_shutdown_policy: invalid input len!");
1149 *dataLen = 0;
1150 return IPMI_CC_REQ_DATA_LEN_INVALID;
1151 }
1152
1153 *dataLen = 0;
1154 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
1155 {
1156 phosphor::logging::log<phosphor::logging::level::ERR>(
1157 "oem_set_shutdown_policy: invalid input!");
1158 return IPMI_CC_INVALID_FIELD_REQUEST;
1159 }
1160
Yong Li0669d192019-05-06 14:01:46 +08001161 if (*req == noShutdownOnOCOT)
1162 {
1163 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1164 Policy::NoShutdownOnOCOT;
1165 }
1166 else
1167 {
1168 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1169 Policy::ShutdownOnOCOT;
1170 }
1171
Yong Li703922d2018-11-06 13:25:31 +08001172 try
1173 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001174 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001175 std::string service = getService(*dbus, oemShutdownPolicyIntf,
1176 oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +08001177 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001178 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +08001179 oemShutdownPolicyObjPathProp,
1180 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +08001181 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001182 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001183 {
1184 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1185 return IPMI_CC_UNSPECIFIED_ERROR;
1186 }
1187
1188 return IPMI_CC_OK;
1189}
1190
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301191/** @brief implementation for check the DHCP or not in IPv4
1192 * @param[in] Channel - Channel number
1193 * @returns true or false.
1194 */
1195static bool isDHCPEnabled(uint8_t Channel)
1196{
1197 try
1198 {
1199 auto ethdevice = getChannelName(Channel);
1200 if (ethdevice.empty())
1201 {
1202 return false;
1203 }
1204 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001205 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001206 auto ethernetObj = getDbusObject(*dbus, networkIPIntf, networkRoot,
1207 ethIP);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001208 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301209 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001210 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301211 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1212 {
1213 return true;
1214 }
1215 else
1216 {
1217 return false;
1218 }
1219 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001220 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301221 {
1222 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1223 return true;
1224 }
1225}
1226
1227/** @brief implementes for check the DHCP or not in IPv6
1228 * @param[in] Channel - Channel number
1229 * @returns true or false.
1230 */
1231static bool isDHCPIPv6Enabled(uint8_t Channel)
1232{
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301233 try
1234 {
1235 auto ethdevice = getChannelName(Channel);
1236 if (ethdevice.empty())
1237 {
1238 return false;
1239 }
1240 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001241 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001242 auto objectInfo = getDbusObject(*dbus, networkIPIntf, networkRoot,
1243 ethIP);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001244 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301245 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001246 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301247 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1248 {
1249 return true;
1250 }
1251 else
1252 {
1253 return false;
1254 }
1255 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001256 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301257 {
1258 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1259 return true;
1260 }
1261}
1262
1263/** @brief implementes the creating of default new user
1264 * @param[in] userName - new username in 16 bytes.
1265 * @param[in] userPassword - new password in 20 bytes
1266 * @returns ipmi completion code.
1267 */
1268ipmi::RspType<> ipmiOEMSetUser2Activation(
1269 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001270 const SecureBuffer& userPassword)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301271{
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001272 if (userPassword.size() != ipmi::maxIpmi20PasswordSize)
1273 {
1274 return ipmi::responseReqDataLenInvalid();
1275 }
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301276 bool userState = false;
1277 // Check for System Interface not exist and LAN should be static
1278 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1279 {
Manish Baing440f62b2021-07-15 22:00:37 +00001280 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301281 try
1282 {
1283 getChannelInfo(channel, chInfo);
1284 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001285 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301286 {
1287 phosphor::logging::log<phosphor::logging::level::ERR>(
1288 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1289 phosphor::logging::entry("MSG: %s", e.description()));
1290 return ipmi::response(ipmi::ccUnspecifiedError);
1291 }
1292 if (chInfo.mediumType ==
1293 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1294 {
1295 phosphor::logging::log<phosphor::logging::level::ERR>(
1296 "ipmiOEMSetUser2Activation: system interface exist .");
1297 return ipmi::response(ipmi::ccCommandNotAvailable);
1298 }
1299 else
1300 {
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301301 if (chInfo.mediumType ==
1302 static_cast<uint8_t>(EChannelMediumType::lan8032))
1303 {
1304 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1305 {
1306 phosphor::logging::log<phosphor::logging::level::ERR>(
1307 "ipmiOEMSetUser2Activation: DHCP enabled .");
1308 return ipmi::response(ipmi::ccCommandNotAvailable);
1309 }
1310 }
1311 }
1312 }
1313 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1314 if (ipmi::ccSuccess ==
1315 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1316 {
1317 if (enabledUsers > 1)
1318 {
1319 phosphor::logging::log<phosphor::logging::level::ERR>(
1320 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1321 return ipmi::response(ipmi::ccCommandNotAvailable);
1322 }
1323 // Check the user 2 is enabled or not
1324 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1325 if (userState == true)
1326 {
1327 phosphor::logging::log<phosphor::logging::level::ERR>(
1328 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1329 return ipmi::response(ipmi::ccCommandNotAvailable);
1330 }
1331 }
1332 else
1333 {
1334 return ipmi::response(ipmi::ccUnspecifiedError);
1335 }
1336
1337#if BYTE_ORDER == LITTLE_ENDIAN
1338 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1339#endif
1340#if BYTE_ORDER == BIG_ENDIAN
1341 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1342#endif
1343
Vernon Mauery037cabd2020-05-14 12:16:01 -07001344 // ipmiUserSetUserName correctly handles char*, possibly non-null
1345 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001346 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1347 sizeof(userName));
1348 const std::string userNameRaw(
1349 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001350
Vernon Mauery037cabd2020-05-14 12:16:01 -07001351 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301352 {
1353 if (ipmi::ccSuccess ==
1354 ipmiUserSetUserPassword(
1355 ipmiDefaultUserId,
1356 reinterpret_cast<const char*>(userPassword.data())))
1357 {
1358 if (ipmi::ccSuccess ==
1359 ipmiUserSetPrivilegeAccess(
1360 ipmiDefaultUserId,
1361 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1362 privAccess, true))
1363 {
1364 phosphor::logging::log<phosphor::logging::level::INFO>(
1365 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001366
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301367 return ipmi::responseSuccess();
1368 }
1369 }
1370 // we need to delete the default user id which added in this command as
1371 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001372 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301373 phosphor::logging::log<phosphor::logging::level::ERR>(
1374 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1375 }
1376 else
1377 {
1378 phosphor::logging::log<phosphor::logging::level::ERR>(
1379 "ipmiOEMSetUser2Activation: Setting username failed.");
1380 }
1381
1382 return ipmi::response(ipmi::ccCommandNotAvailable);
1383}
1384
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301385/** @brief implementes executing the linux command
1386 * @param[in] linux command
1387 * @returns status
1388 */
1389
1390static uint8_t executeCmd(const char* path)
1391{
1392 boost::process::child execProg(path);
1393 execProg.wait();
1394
1395 int retCode = execProg.exit_code();
1396 if (retCode)
1397 {
1398 return ipmi::ccUnspecifiedError;
1399 }
1400 return ipmi::ccSuccess;
1401}
1402
1403/** @brief implementes ASD Security event logging
1404 * @param[in] Event message string
1405 * @param[in] Event Severity
1406 * @returns status
1407 */
1408
1409static void atScaleDebugEventlog(std::string msg, int severity)
1410{
1411 std::string eventStr = "OpenBMC.0.1." + msg;
1412 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1413 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1414 eventStr.c_str(), NULL);
1415}
1416
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301417/** @brief implementes setting password for special user
1418 * @param[in] specialUserIndex
1419 * @param[in] userPassword - new password in 20 bytes
1420 * @returns ipmi completion code.
1421 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07001422ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr& ctx,
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301423 uint8_t specialUserIndex,
1424 std::vector<uint8_t> userPassword)
1425{
1426 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301427 ipmi_ret_t status = ipmi::ccSuccess;
1428
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301429 try
1430 {
1431 getChannelInfo(ctx->channel, chInfo);
1432 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001433 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301434 {
1435 phosphor::logging::log<phosphor::logging::level::ERR>(
1436 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1437 phosphor::logging::entry("MSG: %s", e.description()));
1438 return ipmi::responseUnspecifiedError();
1439 }
1440 if (chInfo.mediumType !=
1441 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1442 {
1443 phosphor::logging::log<phosphor::logging::level::ERR>(
1444 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1445 "interface");
1446 return ipmi::responseCommandNotAvailable();
1447 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301448
1449 // 0 for root user and 1 for AtScaleDebug is allowed
1450 if (specialUserIndex >
1451 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301452 {
1453 phosphor::logging::log<phosphor::logging::level::ERR>(
1454 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1455 return ipmi::responseParmOutOfRange();
1456 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301457 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301458 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301459 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001460 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301461 if (userPassword.size() < minPasswordSizeRequired ||
1462 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1463 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001464 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301465 return ipmi::responseReqDataLenInvalid();
1466 }
1467 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1468 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001469 // Clear sensitive data
1470 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301471 if (specialUserIndex ==
1472 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1473 {
1474 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1475
1476 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1477 }
1478 else
1479 {
1480 status = ipmiSetSpecialUserPassword("root", passwd);
1481 }
1482 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301483 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301484 else
1485 {
1486 if (specialUserIndex ==
1487 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1488 {
1489 status = executeCmd("passwd -d root");
1490 }
1491 else
1492 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301493 status = executeCmd("passwd -d asdbg");
1494
1495 if (status == 0)
1496 {
1497 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1498 LOG_INFO);
1499 }
1500 }
1501 return ipmi::response(status);
1502 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301503}
1504
Kuiying Wang45f04982018-12-26 09:23:08 +08001505namespace ledAction
1506{
1507using namespace sdbusplus::xyz::openbmc_project::Led::server;
1508std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001509 {Physical::Action::Off, 0},
1510 {Physical::Action::On, 2},
1511 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001512
1513std::map<uint8_t, std::string> offsetObjPath = {
1514 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1515
1516} // namespace ledAction
1517
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001518int8_t getLEDState(sdbusplus::bus_t& bus, const std::string& intf,
Kuiying Wang45f04982018-12-26 09:23:08 +08001519 const std::string& objPath, uint8_t& state)
1520{
1521 try
1522 {
1523 std::string service = getService(bus, intf, objPath);
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001524 Value stateValue = getDbusProperty(bus, service, objPath, intf,
1525 "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001526 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001527 state = ledAction::actionDbusToIpmi.at(
1528 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1529 convertActionFromString(strState));
1530 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001531 catch (const sdbusplus::exception_t& e)
Kuiying Wang45f04982018-12-26 09:23:08 +08001532 {
1533 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1534 return -1;
1535 }
1536 return 0;
1537}
1538
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001539ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001540{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001541 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001542 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001543 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001544 for (auto it = ledAction::offsetObjPath.begin();
1545 it != ledAction::offsetObjPath.end(); ++it)
1546 {
1547 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001548 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001549 {
1550 phosphor::logging::log<phosphor::logging::level::ERR>(
1551 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001552 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001553 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001554 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001555 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001556 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001557}
1558
Vernon Mauerydcff1502022-09-28 11:12:46 -07001559ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t, ipmi_cmd_t,
Yong Li23737fe2019-02-19 08:49:55 +08001560 ipmi_request_t request,
1561 ipmi_response_t response,
1562 ipmi_data_len_t dataLen,
Vernon Mauerydcff1502022-09-28 11:12:46 -07001563 ipmi_context_t)
Yong Li23737fe2019-02-19 08:49:55 +08001564{
1565 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1566 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1567
1568 if (*dataLen == 0)
1569 {
1570 phosphor::logging::log<phosphor::logging::level::ERR>(
1571 "CfgHostSerial: invalid input len!",
1572 phosphor::logging::entry("LEN=%d", *dataLen));
1573 return IPMI_CC_REQ_DATA_LEN_INVALID;
1574 }
1575
1576 switch (req->command)
1577 {
1578 case getHostSerialCfgCmd:
1579 {
1580 if (*dataLen != 1)
1581 {
1582 phosphor::logging::log<phosphor::logging::level::ERR>(
1583 "CfgHostSerial: invalid input len!");
1584 *dataLen = 0;
1585 return IPMI_CC_REQ_DATA_LEN_INVALID;
1586 }
1587
1588 *dataLen = 0;
1589
1590 boost::process::ipstream is;
1591 std::vector<std::string> data;
1592 std::string line;
1593 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1594 boost::process::std_out > is);
1595
1596 while (c1.running() && std::getline(is, line) && !line.empty())
1597 {
1598 data.push_back(line);
1599 }
1600
1601 c1.wait();
1602 if (c1.exit_code())
1603 {
1604 phosphor::logging::log<phosphor::logging::level::ERR>(
1605 "CfgHostSerial:: error on execute",
1606 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1607 // Using the default value
1608 *resp = 0;
1609 }
1610 else
1611 {
1612 if (data.size() != 1)
1613 {
1614 phosphor::logging::log<phosphor::logging::level::ERR>(
1615 "CfgHostSerial:: error on read env");
1616 return IPMI_CC_UNSPECIFIED_ERROR;
1617 }
1618 try
1619 {
1620 unsigned long tmp = std::stoul(data[0]);
1621 if (tmp > std::numeric_limits<uint8_t>::max())
1622 {
1623 throw std::out_of_range("Out of range");
1624 }
1625 *resp = static_cast<uint8_t>(tmp);
1626 }
1627 catch (const std::invalid_argument& e)
1628 {
1629 phosphor::logging::log<phosphor::logging::level::ERR>(
1630 "invalid config ",
1631 phosphor::logging::entry("ERR=%s", e.what()));
1632 return IPMI_CC_UNSPECIFIED_ERROR;
1633 }
1634 catch (const std::out_of_range& e)
1635 {
1636 phosphor::logging::log<phosphor::logging::level::ERR>(
1637 "out_of_range config ",
1638 phosphor::logging::entry("ERR=%s", e.what()));
1639 return IPMI_CC_UNSPECIFIED_ERROR;
1640 }
1641 }
1642
1643 *dataLen = 1;
1644 break;
1645 }
1646 case setHostSerialCfgCmd:
1647 {
1648 if (*dataLen != sizeof(CfgHostSerialReq))
1649 {
1650 phosphor::logging::log<phosphor::logging::level::ERR>(
1651 "CfgHostSerial: invalid input len!");
1652 *dataLen = 0;
1653 return IPMI_CC_REQ_DATA_LEN_INVALID;
1654 }
1655
1656 *dataLen = 0;
1657
1658 if (req->parameter > HostSerialCfgParamMax)
1659 {
1660 phosphor::logging::log<phosphor::logging::level::ERR>(
1661 "CfgHostSerial: invalid input!");
1662 return IPMI_CC_INVALID_FIELD_REQUEST;
1663 }
1664
1665 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1666 std::to_string(req->parameter));
1667
1668 c1.wait();
1669 if (c1.exit_code())
1670 {
1671 phosphor::logging::log<phosphor::logging::level::ERR>(
1672 "CfgHostSerial:: error on execute",
1673 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1674 return IPMI_CC_UNSPECIFIED_ERROR;
1675 }
1676 break;
1677 }
1678 default:
1679 phosphor::logging::log<phosphor::logging::level::ERR>(
1680 "CfgHostSerial: invalid input!");
1681 *dataLen = 0;
1682 return IPMI_CC_INVALID_FIELD_REQUEST;
1683 }
1684
1685 return IPMI_CC_OK;
1686}
1687
James Feist91244a62019-02-19 15:04:54 -08001688constexpr const char* thermalModeInterface =
1689 "xyz.openbmc_project.Control.ThermalMode";
1690constexpr const char* thermalModePath =
1691 "/xyz/openbmc_project/control/thermal_mode";
1692
1693bool getFanProfileInterface(
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001694 sdbusplus::bus_t& bus,
Jason M. Bills0748c692022-09-08 15:34:08 -07001695 boost::container::flat_map<std::string, ipmi::DbusVariant>& resp)
James Feist91244a62019-02-19 15:04:54 -08001696{
1697 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1698 "GetAll");
1699 call.append(thermalModeInterface);
1700 try
1701 {
1702 auto data = bus.call(call);
1703 data.read(resp);
1704 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001705 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001706 {
1707 phosphor::logging::log<phosphor::logging::level::ERR>(
1708 "getFanProfileInterface: can't get thermal mode!",
1709 phosphor::logging::entry("ERR=%s", e.what()));
1710 return false;
1711 }
1712 return true;
1713}
1714
anil kumar appanaf945eee2019-09-25 23:29:11 +00001715/**@brief implements the OEM set fan config.
1716 * @param selectedFanProfile - fan profile to enable
1717 * @param reserved1
1718 * @param performanceMode - Performance/Acoustic mode
1719 * @param reserved2
1720 * @param setPerformanceMode - set Performance/Acoustic mode
1721 * @param setFanProfile - set fan profile
1722 *
1723 * @return IPMI completion code.
1724 **/
Vernon Mauerydcff1502022-09-28 11:12:46 -07001725ipmi::RspType<> ipmiOEMSetFanConfig(
1726 [[maybe_unused]] uint8_t selectedFanProfile, uint2_t reserved1,
1727 bool performanceMode, uint3_t reserved2, bool setPerformanceMode,
1728 [[maybe_unused]] bool setFanProfile, std::optional<uint8_t> dimmGroupId,
1729 [[maybe_unused]] std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001730{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001731 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001732 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001733 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001734 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301735
1736 if (dimmGroupId)
1737 {
1738 if (*dimmGroupId >= maxCPUNum)
1739 {
1740 return ipmi::responseInvalidFieldRequest();
1741 }
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001742 if (!cpuPresent("cpu" + std::to_string(*dimmGroupId)))
Joshi-Mansi619186d2020-01-27 19:16:03 +05301743 {
1744 return ipmi::responseInvalidFieldRequest();
1745 }
1746 }
1747
James Feist91244a62019-02-19 15:04:54 -08001748 // todo: tell bios to only send first 2 bytes
Jason M. Bills0748c692022-09-08 15:34:08 -07001749 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001750 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1751 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001752 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001753 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001754 }
1755
1756 std::vector<std::string>* supported =
1757 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1758 if (supported == nullptr)
1759 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001760 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001761 }
1762 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001763 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001764 {
James Feist91244a62019-02-19 15:04:54 -08001765 if (performanceMode)
1766 {
James Feist91244a62019-02-19 15:04:54 -08001767 if (std::find(supported->begin(), supported->end(),
1768 "Performance") != supported->end())
1769 {
1770 mode = "Performance";
1771 }
1772 }
1773 else
1774 {
James Feist91244a62019-02-19 15:04:54 -08001775 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1776 supported->end())
1777 {
1778 mode = "Acoustic";
1779 }
1780 }
1781 if (mode.empty())
1782 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001783 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001784 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001785
1786 try
1787 {
1788 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1789 thermalModeInterface, "Current", mode);
1790 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001791 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001792 {
1793 phosphor::logging::log<phosphor::logging::level::ERR>(
1794 "ipmiOEMSetFanConfig: can't set thermal mode!",
1795 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1796 return ipmi::responseResponseError();
1797 }
James Feist91244a62019-02-19 15:04:54 -08001798 }
1799
anil kumar appanaf945eee2019-09-25 23:29:11 +00001800 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001801}
1802
James Feist5b693632019-07-09 09:06:09 -07001803ipmi::RspType<uint8_t, // profile support map
1804 uint8_t, // fan control profile enable
1805 uint8_t, // flags
1806 uint32_t // dimm presence bit map
1807 >
1808 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001809{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301810 if (dimmGroupId >= maxCPUNum)
1811 {
1812 return ipmi::responseInvalidFieldRequest();
1813 }
1814
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001815 bool cpuStatus = cpuPresent("cpu" + std::to_string(dimmGroupId));
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301816
1817 if (!cpuStatus)
1818 {
1819 return ipmi::responseInvalidFieldRequest();
1820 }
1821
Jason M. Bills0748c692022-09-08 15:34:08 -07001822 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
James Feist91244a62019-02-19 15:04:54 -08001823
Vernon Mauery15419dd2019-05-24 09:40:30 -07001824 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1825 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001826 {
James Feist5b693632019-07-09 09:06:09 -07001827 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001828 }
1829
1830 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1831
1832 if (current == nullptr)
1833 {
1834 phosphor::logging::log<phosphor::logging::level::ERR>(
1835 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001836 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001837 }
1838 bool performance = (*current == "Performance");
1839
James Feist5b693632019-07-09 09:06:09 -07001840 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001841 if (performance)
1842 {
James Feist5b693632019-07-09 09:06:09 -07001843 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001844 }
1845
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001846 constexpr uint8_t fanControlDefaultProfile = 0x80;
1847 constexpr uint8_t fanControlProfileState = 0x00;
1848 constexpr uint32_t dimmPresenceBitmap = 0x00;
1849
1850 return ipmi::responseSuccess(fanControlDefaultProfile,
1851 fanControlProfileState, flags,
1852 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001853}
James Feist5f957ca2019-03-14 15:33:55 -07001854constexpr const char* cfmLimitSettingPath =
1855 "/xyz/openbmc_project/control/cfm_limit";
1856constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001857constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001858constexpr const size_t legacyPCHSensorNumber = 0x22;
1859constexpr const char* exitAirPathName = "Exit_Air";
1860constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001861constexpr const char* pidConfigurationIface =
1862 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001863
James Feist09f6b602019-08-08 11:30:03 -07001864static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001865{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001866 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001867 auto method = dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1868 "/xyz/openbmc_project/object_mapper",
1869 "xyz.openbmc_project.ObjectMapper",
1870 "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001871
James Feistacc8a4e2019-04-02 14:23:57 -07001872 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001873 std::string path;
1874 GetSubTreeType resp;
1875 try
1876 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001877 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001878 reply.read(resp);
1879 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001880 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001881 {
1882 phosphor::logging::log<phosphor::logging::level::ERR>(
1883 "ipmiOEMGetFscParameter: mapper error");
1884 };
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001885 auto config = std::find_if(resp.begin(), resp.end(),
1886 [&name](const auto& pair) {
1887 return pair.first.find(name) != std::string::npos;
1888 });
James Feistfaa4f222019-03-21 16:21:55 -07001889 if (config != resp.end())
1890 {
1891 path = std::move(config->first);
1892 }
1893 return path;
1894}
James Feist5f957ca2019-03-14 15:33:55 -07001895
James Feistacc8a4e2019-04-02 14:23:57 -07001896// flat map to make alphabetical
1897static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1898{
1899 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001900 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001901 auto method = dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1902 "/xyz/openbmc_project/object_mapper",
1903 "xyz.openbmc_project.ObjectMapper",
1904 "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001905
1906 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1907 GetSubTreeType resp;
1908
1909 try
1910 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001911 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001912 reply.read(resp);
1913 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001914 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001915 {
1916 phosphor::logging::log<phosphor::logging::level::ERR>(
1917 "getFanConfigPaths: mapper error");
1918 };
1919 for (const auto& [path, objects] : resp)
1920 {
1921 if (objects.empty())
1922 {
1923 continue; // should be impossible
1924 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001925
1926 try
1927 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001928 ret.emplace(path,
1929 getAllDbusProperties(*dbus, objects[0].first, path,
1930 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001931 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001932 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001933 {
1934 phosphor::logging::log<phosphor::logging::level::ERR>(
1935 "getPidConfigs: can't get DbusProperties!",
1936 phosphor::logging::entry("ERR=%s", e.what()));
1937 }
James Feistacc8a4e2019-04-02 14:23:57 -07001938 }
1939 return ret;
1940}
1941
1942ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1943{
1944 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1945 if (data.empty())
1946 {
1947 return ipmi::responseResponseError();
1948 }
1949 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1950 for (const auto& [_, pid] : data)
1951 {
1952 auto findClass = pid.find("Class");
1953 if (findClass == pid.end())
1954 {
1955 phosphor::logging::log<phosphor::logging::level::ERR>(
1956 "ipmiOEMGetFscParameter: found illegal pid "
1957 "configurations");
1958 return ipmi::responseResponseError();
1959 }
1960 std::string type = std::get<std::string>(findClass->second);
1961 if (type == "fan")
1962 {
1963 auto findOutLimit = pid.find("OutLimitMin");
1964 if (findOutLimit == pid.end())
1965 {
1966 phosphor::logging::log<phosphor::logging::level::ERR>(
1967 "ipmiOEMGetFscParameter: found illegal pid "
1968 "configurations");
1969 return ipmi::responseResponseError();
1970 }
1971 // get the min out of all the offsets
1972 minOffset = std::min(
1973 minOffset,
1974 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1975 }
1976 }
1977 if (minOffset == std::numeric_limits<uint8_t>::max())
1978 {
1979 phosphor::logging::log<phosphor::logging::level::ERR>(
1980 "ipmiOEMGetFscParameter: found no fan configurations!");
1981 return ipmi::responseResponseError();
1982 }
1983
1984 return ipmi::responseSuccess(minOffset);
1985}
1986
1987ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1988{
Manish Baingbaa579f2021-10-08 22:30:32 +00001989 constexpr uint8_t maxFanSpeedOffset = 100;
1990 if (offset > maxFanSpeedOffset)
1991 {
1992 phosphor::logging::log<phosphor::logging::level::ERR>(
1993 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1994 return ipmi::responseInvalidFieldRequest();
1995 }
James Feistacc8a4e2019-04-02 14:23:57 -07001996 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1997 if (data.empty())
1998 {
James Feistacc8a4e2019-04-02 14:23:57 -07001999 phosphor::logging::log<phosphor::logging::level::ERR>(
2000 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
2001 return ipmi::responseResponseError();
2002 }
2003
Vernon Mauery15419dd2019-05-24 09:40:30 -07002004 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002005 bool found = false;
2006 for (const auto& [path, pid] : data)
2007 {
2008 auto findClass = pid.find("Class");
2009 if (findClass == pid.end())
2010 {
James Feistacc8a4e2019-04-02 14:23:57 -07002011 phosphor::logging::log<phosphor::logging::level::ERR>(
2012 "ipmiOEMSetFanSpeedOffset: found illegal pid "
2013 "configurations");
2014 return ipmi::responseResponseError();
2015 }
2016 std::string type = std::get<std::string>(findClass->second);
2017 if (type == "fan")
2018 {
2019 auto findOutLimit = pid.find("OutLimitMin");
2020 if (findOutLimit == pid.end())
2021 {
James Feistacc8a4e2019-04-02 14:23:57 -07002022 phosphor::logging::log<phosphor::logging::level::ERR>(
2023 "ipmiOEMSetFanSpeedOffset: found illegal pid "
2024 "configurations");
2025 return ipmi::responseResponseError();
2026 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07002027 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07002028 path, pidConfigurationIface, "OutLimitMin",
2029 static_cast<double>(offset));
2030 found = true;
2031 }
2032 }
2033 if (!found)
2034 {
2035 phosphor::logging::log<phosphor::logging::level::ERR>(
2036 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
2037 return ipmi::responseResponseError();
2038 }
2039
2040 return ipmi::responseSuccess();
2041}
2042
2043ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
2044 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07002045{
2046 constexpr const size_t disableLimiting = 0x0;
2047
Vernon Mauery15419dd2019-05-24 09:40:30 -07002048 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002049 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002050 {
James Feist09f6b602019-08-08 11:30:03 -07002051 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07002052 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07002053 {
James Feist09f6b602019-08-08 11:30:03 -07002054 pathName = exitAirPathName;
2055 }
2056 else if (param1 == legacyPCHSensorNumber)
2057 {
2058 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07002059 }
2060 else
2061 {
James Feistacc8a4e2019-04-02 14:23:57 -07002062 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002063 }
James Feist09f6b602019-08-08 11:30:03 -07002064 std::string path = getConfigPath(pathName);
2065 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
2066 pidConfigurationIface, "SetPoint",
2067 static_cast<double>(param2));
2068 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07002069 }
James Feistacc8a4e2019-04-02 14:23:57 -07002070 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002071 {
James Feistacc8a4e2019-04-02 14:23:57 -07002072 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07002073
2074 // must be greater than 50 based on eps
2075 if (cfm < 50 && cfm != disableLimiting)
2076 {
James Feistacc8a4e2019-04-02 14:23:57 -07002077 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002078 }
2079
2080 try
2081 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002082 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07002083 cfmLimitIface, "Limit",
2084 static_cast<double>(cfm));
2085 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002086 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002087 {
2088 phosphor::logging::log<phosphor::logging::level::ERR>(
2089 "ipmiOEMSetFscParameter: can't set cfm setting!",
2090 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002091 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002092 }
James Feistacc8a4e2019-04-02 14:23:57 -07002093 return ipmi::responseSuccess();
2094 }
2095 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2096 {
James Feistacc8a4e2019-04-02 14:23:57 -07002097 uint8_t requestedDomainMask = param1;
2098 boost::container::flat_map data = getPidConfigs();
2099 if (data.empty())
2100 {
James Feistacc8a4e2019-04-02 14:23:57 -07002101 phosphor::logging::log<phosphor::logging::level::ERR>(
2102 "ipmiOEMSetFscParameter: found no pid configurations!");
2103 return ipmi::responseResponseError();
2104 }
2105 size_t count = 0;
2106 for (const auto& [path, pid] : data)
2107 {
2108 auto findClass = pid.find("Class");
2109 if (findClass == pid.end())
2110 {
James Feistacc8a4e2019-04-02 14:23:57 -07002111 phosphor::logging::log<phosphor::logging::level::ERR>(
2112 "ipmiOEMSetFscParameter: found illegal pid "
2113 "configurations");
2114 return ipmi::responseResponseError();
2115 }
2116 std::string type = std::get<std::string>(findClass->second);
2117 if (type == "fan")
2118 {
2119 if (requestedDomainMask & (1 << count))
2120 {
2121 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002122 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07002123 pidConfigurationIface, "OutLimitMax",
2124 static_cast<double>(param2));
2125 }
2126 count++;
2127 }
2128 }
2129 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07002130 }
2131 else
2132 {
2133 // todo other command parts possibly
2134 // tcontrol is handled in peci now
2135 // fan speed offset not implemented yet
2136 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002137 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002138 }
2139}
2140
James Feistacc8a4e2019-04-02 14:23:57 -07002141ipmi::RspType<
2142 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2143 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002144{
James Feist09f6b602019-08-08 11:30:03 -07002145 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002146
Vernon Mauery15419dd2019-05-24 09:40:30 -07002147 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002148 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002149 {
James Feistacc8a4e2019-04-02 14:23:57 -07002150 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002151 {
James Feistacc8a4e2019-04-02 14:23:57 -07002152 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002153 }
2154
James Feist09f6b602019-08-08 11:30:03 -07002155 std::string pathName;
2156
2157 if (*param == legacyExitAirSensorNumber)
2158 {
2159 pathName = exitAirPathName;
2160 }
2161 else if (*param == legacyPCHSensorNumber)
2162 {
2163 pathName = pchPathName;
2164 }
2165 else
James Feistfaa4f222019-03-21 16:21:55 -07002166 {
James Feistacc8a4e2019-04-02 14:23:57 -07002167 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002168 }
James Feist09f6b602019-08-08 11:30:03 -07002169
2170 uint8_t setpoint = legacyDefaultSetpoint;
2171 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002172 if (path.size())
2173 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002174 Value val = ipmi::getDbusProperty(
2175 *dbus, "xyz.openbmc_project.EntityManager", path,
2176 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002177 setpoint = std::floor(std::get<double>(val) + 0.5);
2178 }
2179
2180 // old implementation used to return the "default" and current, we
2181 // don't make the default readily available so just make both the
2182 // same
James Feistfaa4f222019-03-21 16:21:55 -07002183
James Feistacc8a4e2019-04-02 14:23:57 -07002184 return ipmi::responseSuccess(
2185 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002186 }
James Feistacc8a4e2019-04-02 14:23:57 -07002187 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2188 {
2189 constexpr const size_t maxDomainCount = 8;
2190
2191 if (!param)
2192 {
2193 return ipmi::responseReqDataLenInvalid();
2194 }
2195 uint8_t requestedDomain = *param;
2196 if (requestedDomain >= maxDomainCount)
2197 {
2198 return ipmi::responseInvalidFieldRequest();
2199 }
2200
2201 boost::container::flat_map data = getPidConfigs();
2202 if (data.empty())
2203 {
2204 phosphor::logging::log<phosphor::logging::level::ERR>(
2205 "ipmiOEMGetFscParameter: found no pid configurations!");
2206 return ipmi::responseResponseError();
2207 }
2208 size_t count = 0;
2209 for (const auto& [_, pid] : data)
2210 {
2211 auto findClass = pid.find("Class");
2212 if (findClass == pid.end())
2213 {
2214 phosphor::logging::log<phosphor::logging::level::ERR>(
2215 "ipmiOEMGetFscParameter: found illegal pid "
2216 "configurations");
2217 return ipmi::responseResponseError();
2218 }
2219 std::string type = std::get<std::string>(findClass->second);
2220 if (type == "fan")
2221 {
2222 if (requestedDomain == count)
2223 {
2224 auto findOutLimit = pid.find("OutLimitMax");
2225 if (findOutLimit == pid.end())
2226 {
2227 phosphor::logging::log<phosphor::logging::level::ERR>(
2228 "ipmiOEMGetFscParameter: found illegal pid "
2229 "configurations");
2230 return ipmi::responseResponseError();
2231 }
2232
2233 return ipmi::responseSuccess(
2234 static_cast<uint8_t>(std::floor(
2235 std::get<double>(findOutLimit->second) + 0.5)));
2236 }
2237 else
2238 {
2239 count++;
2240 }
2241 }
2242 }
2243
2244 return ipmi::responseInvalidFieldRequest();
2245 }
2246 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002247 {
James Feist5f957ca2019-03-14 15:33:55 -07002248 /*
2249 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002250 previous behavior didn't seem to prevent this, ignore the check for
2251 now.
James Feist5f957ca2019-03-14 15:33:55 -07002252
James Feistacc8a4e2019-04-02 14:23:57 -07002253 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002254 {
2255 phosphor::logging::log<phosphor::logging::level::ERR>(
2256 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002257 return IPMI_CC_REQ_DATA_LEN_INVALID;
2258 }
2259 */
2260 Value cfmLimit;
2261 Value cfmMaximum;
2262 try
2263 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002264 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002265 cfmLimitSettingPath, cfmLimitIface,
2266 "Limit");
2267 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002268 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002269 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2270 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002271 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002272 {
2273 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002274 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002275 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002276 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002277 }
2278
James Feistacc8a4e2019-04-02 14:23:57 -07002279 double cfmMax = std::get<double>(cfmMaximum);
2280 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002281
James Feistacc8a4e2019-04-02 14:23:57 -07002282 cfmLim = std::floor(cfmLim + 0.5);
2283 cfmMax = std::floor(cfmMax + 0.5);
2284 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2285 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002286
James Feistacc8a4e2019-04-02 14:23:57 -07002287 return ipmi::responseSuccess(
2288 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002289 }
James Feistacc8a4e2019-04-02 14:23:57 -07002290
James Feist5f957ca2019-03-14 15:33:55 -07002291 else
2292 {
2293 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002294 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002295 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002296 }
2297}
2298
Jason M. Bills0748c692022-09-08 15:34:08 -07002299using crConfigVariant = ipmi::DbusVariant;
Cheng C Yang773703a2019-08-15 09:41:11 +08002300
Vernon Mauerydcff1502022-09-28 11:12:46 -07002301int setCRConfig(ipmi::Context::ptr& ctx, const std::string& property,
Cheng C Yang773703a2019-08-15 09:41:11 +08002302 const crConfigVariant& value,
Vernon Mauerydcff1502022-09-28 11:12:46 -07002303 [[maybe_unused]] std::chrono::microseconds timeout =
2304 ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002305{
2306 boost::system::error_code ec;
2307 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002308 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002309 "/xyz/openbmc_project/control/power_supply_redundancy",
2310 "org.freedesktop.DBus.Properties", "Set",
2311 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2312 if (ec)
2313 {
2314 phosphor::logging::log<phosphor::logging::level::ERR>(
2315 "Failed to set dbus property to cold redundancy");
2316 return -1;
2317 }
2318
2319 return 0;
2320}
2321
Kuiying Wange45333a2020-07-22 22:06:37 +08002322int getCRConfig(
Vernon Mauerydcff1502022-09-28 11:12:46 -07002323 ipmi::Context::ptr& ctx, const std::string& property,
2324 crConfigVariant& value,
Kuiying Wange45333a2020-07-22 22:06:37 +08002325 const std::string& service = "xyz.openbmc_project.PSURedundancy",
Vernon Mauerydcff1502022-09-28 11:12:46 -07002326 [[maybe_unused]] std::chrono::microseconds timeout =
2327 ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002328{
2329 boost::system::error_code ec;
2330 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002331 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002332 "/xyz/openbmc_project/control/power_supply_redundancy",
2333 "org.freedesktop.DBus.Properties", "Get",
2334 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2335 if (ec)
2336 {
2337 phosphor::logging::log<phosphor::logging::level::ERR>(
2338 "Failed to get dbus property to cold redundancy");
2339 return -1;
2340 }
2341 return 0;
2342}
2343
2344uint8_t getPSUCount(void)
2345{
2346 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2347 ipmi::Value num;
2348 try
2349 {
2350 num = ipmi::getDbusProperty(
2351 *dbus, "xyz.openbmc_project.PSURedundancy",
2352 "/xyz/openbmc_project/control/power_supply_redundancy",
2353 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2354 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002355 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002356 {
2357 phosphor::logging::log<phosphor::logging::level::ERR>(
2358 "Failed to get PSUNumber property from dbus interface");
2359 return 0;
2360 }
2361 uint8_t* pNum = std::get_if<uint8_t>(&num);
2362 if (!pNum)
2363 {
2364 phosphor::logging::log<phosphor::logging::level::ERR>(
2365 "Error to get PSU Number");
2366 return 0;
2367 }
2368 return *pNum;
2369}
2370
2371bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2372{
2373 if (conf.size() < num)
2374 {
2375 phosphor::logging::log<phosphor::logging::level::ERR>(
2376 "Invalid PSU Ranking");
2377 return false;
2378 }
2379 std::set<uint8_t> confSet;
2380 for (uint8_t i = 0; i < num; i++)
2381 {
2382 if (conf[i] > num)
2383 {
2384 phosphor::logging::log<phosphor::logging::level::ERR>(
2385 "PSU Ranking is larger than current PSU number");
2386 return false;
2387 }
2388 confSet.emplace(conf[i]);
2389 }
2390
2391 if (confSet.size() != num)
2392 {
2393 phosphor::logging::log<phosphor::logging::level::ERR>(
2394 "duplicate PSU Ranking");
2395 return false;
2396 }
2397 return true;
2398}
2399
2400enum class crParameter
2401{
2402 crStatus = 0,
2403 crFeature = 1,
2404 rotationFeature = 2,
2405 rotationAlgo = 3,
2406 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002407 numOfPSU = 5,
2408 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002409};
2410
2411constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2412static const constexpr uint32_t oneDay = 0x15180;
2413static const constexpr uint32_t oneMonth = 0xf53700;
2414static const constexpr uint8_t userSpecific = 0x01;
2415static const constexpr uint8_t crSetCompleted = 0;
Vernon Mauerydcff1502022-09-28 11:12:46 -07002416ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr& ctx,
Cheng C Yang773703a2019-08-15 09:41:11 +08002417 uint8_t parameter,
2418 ipmi::message::Payload& payload)
2419{
2420 switch (static_cast<crParameter>(parameter))
2421 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002422 case crParameter::rotationFeature:
2423 {
2424 uint8_t param1;
2425 if (payload.unpack(param1) || !payload.fullyUnpacked())
2426 {
2427 return ipmi::responseReqDataLenInvalid();
2428 }
2429 // Rotation Enable can only be true or false
2430 if (param1 > 1)
2431 {
2432 return ipmi::responseInvalidFieldRequest();
2433 }
2434 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2435 {
2436 return ipmi::responseResponseError();
2437 }
2438 break;
2439 }
2440 case crParameter::rotationAlgo:
2441 {
2442 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2443 std::string algoName;
2444 uint8_t param1;
2445 if (payload.unpack(param1))
2446 {
2447 return ipmi::responseReqDataLenInvalid();
2448 }
2449 switch (param1)
2450 {
2451 case 0:
2452 algoName = "xyz.openbmc_project.Control."
2453 "PowerSupplyRedundancy.Algo.bmcSpecific";
2454 break;
2455 case 1:
2456 algoName = "xyz.openbmc_project.Control."
2457 "PowerSupplyRedundancy.Algo.userSpecific";
2458 break;
2459 default:
2460 return ipmi::responseInvalidFieldRequest();
2461 }
2462 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2463 {
2464 return ipmi::responseResponseError();
2465 }
2466
2467 uint8_t numberOfPSU = getPSUCount();
2468 if (!numberOfPSU)
2469 {
2470 return ipmi::responseResponseError();
2471 }
2472 std::vector<uint8_t> rankOrder;
2473
2474 if (param1 == userSpecific)
2475 {
2476 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2477 {
2478 ipmi::responseReqDataLenInvalid();
2479 }
Yong Li83315132019-10-23 17:42:24 +08002480 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002481 {
2482 return ipmi::responseReqDataLenInvalid();
2483 }
2484
2485 if (!validateCRAlgo(rankOrder, numberOfPSU))
2486 {
2487 return ipmi::responseInvalidFieldRequest();
2488 }
2489 }
2490 else
2491 {
2492 if (rankOrder.size() > 0)
2493 {
2494 return ipmi::responseReqDataLenInvalid();
2495 }
2496 for (uint8_t i = 1; i <= numberOfPSU; i++)
2497 {
2498 rankOrder.emplace_back(i);
2499 }
2500 }
2501 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2502 {
2503 return ipmi::responseResponseError();
2504 }
2505 break;
2506 }
2507 case crParameter::rotationPeriod:
2508 {
2509 // Minimum Rotation period is One day (86400 seconds) and Max
2510 // Rotation Period is 6 month (0xf53700 seconds)
2511 uint32_t period;
2512 if (payload.unpack(period) || !payload.fullyUnpacked())
2513 {
2514 return ipmi::responseReqDataLenInvalid();
2515 }
2516 if ((period < oneDay) || (period > oneMonth))
2517 {
2518 return ipmi::responseInvalidFieldRequest();
2519 }
2520 if (setCRConfig(ctx, "PeriodOfRotation", period))
2521 {
2522 return ipmi::responseResponseError();
2523 }
2524 break;
2525 }
2526 default:
2527 {
2528 return ipmi::response(ccParameterNotSupported);
2529 }
2530 }
2531
Cheng C Yang773703a2019-08-15 09:41:11 +08002532 return ipmi::responseSuccess(crSetCompleted);
2533}
2534
Yong Li83315132019-10-23 17:42:24 +08002535ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Vernon Mauerydcff1502022-09-28 11:12:46 -07002536 ipmiOEMGetCRConfig(ipmi::Context::ptr& ctx, uint8_t parameter)
Cheng C Yang773703a2019-08-15 09:41:11 +08002537{
2538 crConfigVariant value;
2539 switch (static_cast<crParameter>(parameter))
2540 {
2541 case crParameter::crStatus:
2542 {
2543 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2544 {
2545 return ipmi::responseResponseError();
2546 }
2547 std::string* pStatus = std::get_if<std::string>(&value);
2548 if (!pStatus)
2549 {
2550 phosphor::logging::log<phosphor::logging::level::ERR>(
2551 "Error to get ColdRedundancyStatus property");
2552 return ipmi::responseResponseError();
2553 }
2554 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2555 auto status =
2556 server::PowerSupplyRedundancy::convertStatusFromString(
2557 *pStatus);
2558 switch (status)
2559 {
2560 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002561 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002562 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002563
2564 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002565 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002566 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002567 default:
2568 phosphor::logging::log<phosphor::logging::level::ERR>(
2569 "Error to get valid status");
2570 return ipmi::responseResponseError();
2571 }
2572 }
2573 case crParameter::crFeature:
2574 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002575 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002576 {
2577 return ipmi::responseResponseError();
2578 }
2579 bool* pResponse = std::get_if<bool>(&value);
2580 if (!pResponse)
2581 {
2582 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002583 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002584 return ipmi::responseResponseError();
2585 }
2586
Cheng C Yangf41e3342019-09-10 04:47:23 +08002587 return ipmi::responseSuccess(parameter,
2588 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002589 }
2590 case crParameter::rotationFeature:
2591 {
2592 if (getCRConfig(ctx, "RotationEnabled", value))
2593 {
2594 return ipmi::responseResponseError();
2595 }
2596 bool* pResponse = std::get_if<bool>(&value);
2597 if (!pResponse)
2598 {
2599 phosphor::logging::log<phosphor::logging::level::ERR>(
2600 "Error to get RotationEnabled property");
2601 return ipmi::responseResponseError();
2602 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002603 return ipmi::responseSuccess(parameter,
2604 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002605 }
2606 case crParameter::rotationAlgo:
2607 {
2608 if (getCRConfig(ctx, "RotationAlgorithm", value))
2609 {
2610 return ipmi::responseResponseError();
2611 }
2612
2613 std::string* pAlgo = std::get_if<std::string>(&value);
2614 if (!pAlgo)
2615 {
2616 phosphor::logging::log<phosphor::logging::level::ERR>(
2617 "Error to get RotationAlgorithm property");
2618 return ipmi::responseResponseError();
2619 }
Yong Li83315132019-10-23 17:42:24 +08002620 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002621 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2622 auto algo =
2623 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002624
Cheng C Yang773703a2019-08-15 09:41:11 +08002625 switch (algo)
2626 {
2627 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002628 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002629 break;
2630 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002631 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002632 break;
2633 default:
2634 phosphor::logging::log<phosphor::logging::level::ERR>(
2635 "Error to get valid algo");
2636 return ipmi::responseResponseError();
2637 }
2638
2639 if (getCRConfig(ctx, "RotationRankOrder", value))
2640 {
2641 return ipmi::responseResponseError();
2642 }
2643 std::vector<uint8_t>* pResponse =
2644 std::get_if<std::vector<uint8_t>>(&value);
2645 if (!pResponse)
2646 {
2647 phosphor::logging::log<phosphor::logging::level::ERR>(
2648 "Error to get RotationRankOrder property");
2649 return ipmi::responseResponseError();
2650 }
Yong Li83315132019-10-23 17:42:24 +08002651
Cheng C Yang773703a2019-08-15 09:41:11 +08002652 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002653 std::back_inserter(response));
2654
Cheng C Yangf41e3342019-09-10 04:47:23 +08002655 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002656 }
2657 case crParameter::rotationPeriod:
2658 {
2659 if (getCRConfig(ctx, "PeriodOfRotation", value))
2660 {
2661 return ipmi::responseResponseError();
2662 }
2663 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2664 if (!pResponse)
2665 {
2666 phosphor::logging::log<phosphor::logging::level::ERR>(
2667 "Error to get RotationAlgorithm property");
2668 return ipmi::responseResponseError();
2669 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002670 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002671 }
2672 case crParameter::numOfPSU:
2673 {
2674 uint8_t numberOfPSU = getPSUCount();
2675 if (!numberOfPSU)
2676 {
2677 return ipmi::responseResponseError();
2678 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002679 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002680 }
Yong Li19445ab2019-12-20 18:25:29 +08002681 case crParameter::rotationRankOrderEffective:
2682 {
2683 if (getCRConfig(ctx, "RotationRankOrder", value,
2684 "xyz.openbmc_project.PSURedundancy"))
2685 {
2686 return ipmi::responseResponseError();
2687 }
2688 std::vector<uint8_t>* pResponse =
2689 std::get_if<std::vector<uint8_t>>(&value);
2690 if (!pResponse)
2691 {
2692 phosphor::logging::log<phosphor::logging::level::ERR>(
2693 "Error to get effective RotationRankOrder property");
2694 return ipmi::responseResponseError();
2695 }
2696 return ipmi::responseSuccess(parameter, *pResponse);
2697 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002698 default:
2699 {
2700 return ipmi::response(ccParameterNotSupported);
2701 }
2702 }
2703}
2704
Zhu, Yungebe560b02019-04-21 21:19:21 -04002705ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2706 uint8_t faultState,
2707 uint8_t faultGroup,
2708 std::array<uint8_t, 8>& ledStateData)
2709{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002710 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2711 static const std::array<std::string, maxFaultType> faultNames = {
2712 "faultFan", "faultTemp", "faultPower",
2713 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002714
2715 constexpr uint8_t maxFaultSource = 0x4;
2716 constexpr uint8_t skipLEDs = 0xFF;
2717 constexpr uint8_t pinSize = 64;
2718 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002719 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002720
Zhikui Rence4e73f2019-12-06 13:59:47 -08002721 // same pin names need to be defined in dts file
2722 static const std::array<std::array<std::string, groupSize>, groupNum>
2723 faultLedPinNames = {{
2724 "LED_CPU1_CH1_DIMM1_FAULT",
2725 "LED_CPU1_CH1_DIMM2_FAULT",
2726 "LED_CPU1_CH2_DIMM1_FAULT",
2727 "LED_CPU1_CH2_DIMM2_FAULT",
2728 "LED_CPU1_CH3_DIMM1_FAULT",
2729 "LED_CPU1_CH3_DIMM2_FAULT",
2730 "LED_CPU1_CH4_DIMM1_FAULT",
2731 "LED_CPU1_CH4_DIMM2_FAULT",
2732 "LED_CPU1_CH5_DIMM1_FAULT",
2733 "LED_CPU1_CH5_DIMM2_FAULT",
2734 "LED_CPU1_CH6_DIMM1_FAULT",
2735 "LED_CPU1_CH6_DIMM2_FAULT",
2736 "",
2737 "",
2738 "",
2739 "", // end of group1
2740 "LED_CPU2_CH1_DIMM1_FAULT",
2741 "LED_CPU2_CH1_DIMM2_FAULT",
2742 "LED_CPU2_CH2_DIMM1_FAULT",
2743 "LED_CPU2_CH2_DIMM2_FAULT",
2744 "LED_CPU2_CH3_DIMM1_FAULT",
2745 "LED_CPU2_CH3_DIMM2_FAULT",
2746 "LED_CPU2_CH4_DIMM1_FAULT",
2747 "LED_CPU2_CH4_DIMM2_FAULT",
2748 "LED_CPU2_CH5_DIMM1_FAULT",
2749 "LED_CPU2_CH5_DIMM2_FAULT",
2750 "LED_CPU2_CH6_DIMM1_FAULT",
2751 "LED_CPU2_CH6_DIMM2_FAULT",
2752 "",
2753 "",
2754 "",
2755 "", // endof group2
2756 "LED_CPU3_CH1_DIMM1_FAULT",
2757 "LED_CPU3_CH1_DIMM2_FAULT",
2758 "LED_CPU3_CH2_DIMM1_FAULT",
2759 "LED_CPU3_CH2_DIMM2_FAULT",
2760 "LED_CPU3_CH3_DIMM1_FAULT",
2761 "LED_CPU3_CH3_DIMM2_FAULT",
2762 "LED_CPU3_CH4_DIMM1_FAULT",
2763 "LED_CPU3_CH4_DIMM2_FAULT",
2764 "LED_CPU3_CH5_DIMM1_FAULT",
2765 "LED_CPU3_CH5_DIMM2_FAULT",
2766 "LED_CPU3_CH6_DIMM1_FAULT",
2767 "LED_CPU3_CH6_DIMM2_FAULT",
2768 "",
2769 "",
2770 "",
2771 "", // end of group3
2772 "LED_CPU4_CH1_DIMM1_FAULT",
2773 "LED_CPU4_CH1_DIMM2_FAULT",
2774 "LED_CPU4_CH2_DIMM1_FAULT",
2775 "LED_CPU4_CH2_DIMM2_FAULT",
2776 "LED_CPU4_CH3_DIMM1_FAULT",
2777 "LED_CPU4_CH3_DIMM2_FAULT",
2778 "LED_CPU4_CH4_DIMM1_FAULT",
2779 "LED_CPU4_CH4_DIMM2_FAULT",
2780 "LED_CPU4_CH5_DIMM1_FAULT",
2781 "LED_CPU4_CH5_DIMM2_FAULT",
2782 "LED_CPU4_CH6_DIMM1_FAULT",
2783 "LED_CPU4_CH6_DIMM2_FAULT",
2784 "",
2785 "",
2786 "",
2787 "", // end of group4
2788 "LED_FAN1_FAULT",
2789 "LED_FAN2_FAULT",
2790 "LED_FAN3_FAULT",
2791 "LED_FAN4_FAULT",
2792 "LED_FAN5_FAULT",
2793 "LED_FAN6_FAULT",
2794 "LED_FAN7_FAULT",
2795 "LED_FAN8_FAULT",
2796 "",
2797 "",
2798 "",
2799 "",
2800 "",
2801 "",
2802 "",
2803 "" // end of group5
2804 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002805
Zhikui Rence4e73f2019-12-06 13:59:47 -08002806 // Validate the source, fault type --
2807 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2808 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2809 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2810 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2811 // definition differs based on fault type (Byte 2)
2812 // Type Fan=> Group: 0=FanGroupID, FF-not used
2813 // Byte 5-11 00h, not used
2814 // Byte12 FanLedState [7:0]-Fans 7:0
2815 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2816 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2817 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2818 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2819 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2820 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2821 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2822 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002823 if ((sourceId >= maxFaultSource) ||
2824 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2825 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2826 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2827 {
2828 return ipmi::responseParmOutOfRange();
2829 }
2830
Zhikui Rence4e73f2019-12-06 13:59:47 -08002831 size_t pinGroupOffset = 0;
2832 size_t pinGroupMax = pinSize / groupSize;
2833 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002834 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002835 pinGroupOffset = 4;
2836 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002837 }
2838
2839 switch (RemoteFaultType(faultType))
2840 {
2841 case (RemoteFaultType::fan):
2842 case (RemoteFaultType::memory):
2843 {
2844 if (faultGroup == skipLEDs)
2845 {
2846 return ipmi::responseSuccess();
2847 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002848 // calculate led state bit filed count, each byte has 8bits
2849 // the maximum bits will be 8 * 8 bits
2850 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002851
2852 // assemble ledState
2853 uint64_t ledState = 0;
2854 bool hasError = false;
Vernon Mauerydcff1502022-09-28 11:12:46 -07002855 for (size_t i = 0; i < sizeof(ledStateData); i++)
Zhu, Yungebe560b02019-04-21 21:19:21 -04002856 {
2857 ledState = (uint64_t)(ledState << 8);
2858 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2859 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002860 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002861
Vernon Mauerydcff1502022-09-28 11:12:46 -07002862 for (size_t group = 0; group < pinGroupMax; group++)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002863 {
2864 for (int i = 0; i < groupSize; i++)
2865 { // skip non-existing pins
2866 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2867 {
2868 continue;
2869 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002870
Zhikui Rence4e73f2019-12-06 13:59:47 -08002871 gpiod::line line = gpiod::find_line(
2872 faultLedPinNames[group + pinGroupOffset][i]);
2873 if (!line)
2874 {
2875 phosphor::logging::log<phosphor::logging::level::ERR>(
2876 "Not Find Led Gpio Device!",
2877 phosphor::logging::entry(
2878 "DEVICE=%s",
2879 faultLedPinNames[group + pinGroupOffset][i]
2880 .c_str()));
2881 hasError = true;
2882 continue;
2883 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002884
Zhikui Rence4e73f2019-12-06 13:59:47 -08002885 bool activeHigh =
2886 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2887 try
2888 {
2889 line.request(
2890 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2891 activeHigh
2892 ? 0
2893 : gpiod::line_request::FLAG_ACTIVE_LOW});
2894 line.set_value(ledStateBits[i + group * groupSize]);
2895 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002896 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002897 {
2898 phosphor::logging::log<phosphor::logging::level::ERR>(
2899 "Error write Led Gpio Device!",
2900 phosphor::logging::entry(
2901 "DEVICE=%s",
2902 faultLedPinNames[group + pinGroupOffset][i]
2903 .c_str()));
2904 hasError = true;
2905 continue;
2906 }
2907 } // for int i
2908 }
2909 if (hasError)
2910 {
2911 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002912 }
2913 break;
2914 }
2915 default:
2916 {
2917 // now only support two fault types
2918 return ipmi::responseParmOutOfRange();
2919 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002920 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002921 return ipmi::responseSuccess();
2922}
2923
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302924ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2925{
2926 uint8_t prodId = 0;
2927 try
2928 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002929 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302930 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002931 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302932 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2933 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002934 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302935 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2936 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302937 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2938 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002939 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302940 {
2941 phosphor::logging::log<phosphor::logging::level::ERR>(
2942 "ipmiOEMReadBoardProductId: Product ID read failed!",
2943 phosphor::logging::entry("ERR=%s", e.what()));
2944 }
2945 return ipmi::responseSuccess(prodId);
2946}
2947
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302948/** @brief implements the get security mode command
2949 * @param ctx - ctx pointer
2950 *
2951 * @returns IPMI completion code with following data
2952 * - restriction mode value - As specified in
2953 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2954 * - special mode value - As specified in
2955 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2956 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07002957ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr& ctx)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302958{
2959 namespace securityNameSpace =
2960 sdbusplus::xyz::openbmc_project::Control::Security::server;
2961 uint8_t restrictionModeValue = 0;
2962 uint8_t specialModeValue = 0;
2963
2964 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07002965 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07002966 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302967 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2968 restricionModeProperty);
2969 if (ec)
2970 {
2971 phosphor::logging::log<phosphor::logging::level::ERR>(
2972 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2973 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2974 return ipmi::responseUnspecifiedError();
2975 }
2976 restrictionModeValue = static_cast<uint8_t>(
2977 securityNameSpace::RestrictionMode::convertModesFromString(
2978 std::get<std::string>(varRestrMode)));
Jason M. Bills0748c692022-09-08 15:34:08 -07002979 auto varSpecialMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
2980 ctx->yield, ec, specialModeService, specialModeBasePath,
2981 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2982 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302983 if (ec)
2984 {
2985 phosphor::logging::log<phosphor::logging::level::ERR>(
2986 "ipmiGetSecurityMode: failed to get SpecialMode property",
2987 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2988 // fall through, let us not worry about SpecialMode property, which is
2989 // not required in user scenario
2990 }
2991 else
2992 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302993 specialModeValue = static_cast<uint8_t>(
2994 securityNameSpace::SpecialMode::convertModesFromString(
2995 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302996 }
2997 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2998}
2999
3000/** @brief implements the set security mode command
3001 * Command allows to upgrade the restriction mode and won't allow
3002 * to downgrade from system interface
3003 * @param ctx - ctx pointer
3004 * @param restrictionMode - restriction mode value to be set.
3005 *
3006 * @returns IPMI completion code
3007 */
Vernon Mauerydcff1502022-09-28 11:12:46 -07003008ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr& ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303009 uint8_t restrictionMode,
3010 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303011{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303012#ifndef BMC_VALIDATION_UNSECURE_FEATURE
3013 if (specialMode)
3014 {
3015 return ipmi::responseReqDataLenInvalid();
3016 }
3017#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303018 namespace securityNameSpace =
3019 sdbusplus::xyz::openbmc_project::Control::Security::server;
3020
3021 ChannelInfo chInfo;
3022 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
3023 {
3024 phosphor::logging::log<phosphor::logging::level::ERR>(
3025 "ipmiSetSecurityMode: Failed to get Channel Info",
3026 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
3027 return ipmi::responseUnspecifiedError();
3028 }
3029 auto reqMode =
3030 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
3031
3032 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
3033 (reqMode >
3034 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
3035 {
3036 return ipmi::responseInvalidFieldRequest();
3037 }
3038
3039 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07003040 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07003041 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303042 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
3043 restricionModeProperty);
3044 if (ec)
3045 {
3046 phosphor::logging::log<phosphor::logging::level::ERR>(
3047 "ipmiSetSecurityMode: failed to get RestrictionMode property",
3048 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3049 return ipmi::responseUnspecifiedError();
3050 }
3051 auto currentRestrictionMode =
3052 securityNameSpace::RestrictionMode::convertModesFromString(
3053 std::get<std::string>(varRestrMode));
3054
3055 if (chInfo.mediumType !=
3056 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
3057 currentRestrictionMode > reqMode)
3058 {
3059 phosphor::logging::log<phosphor::logging::level::ERR>(
3060 "ipmiSetSecurityMode - Downgrading security mode not supported "
3061 "through system interface",
3062 phosphor::logging::entry(
3063 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
3064 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
3065 return ipmi::responseCommandNotAvailable();
3066 }
3067
3068 ec.clear();
3069 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07003070 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303071 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
3072 restricionModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003073 static_cast<ipmi::DbusVariant>(
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303074 securityNameSpace::convertForMessage(reqMode)));
3075
3076 if (ec)
3077 {
3078 phosphor::logging::log<phosphor::logging::level::ERR>(
3079 "ipmiSetSecurityMode: failed to set RestrictionMode property",
3080 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3081 return ipmi::responseUnspecifiedError();
3082 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303083
3084#ifdef BMC_VALIDATION_UNSECURE_FEATURE
3085 if (specialMode)
3086 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00003087 constexpr uint8_t mfgMode = 0x01;
3088 // Manufacturing mode is reserved. So can't enable this mode.
3089 if (specialMode.value() == mfgMode)
3090 {
3091 phosphor::logging::log<phosphor::logging::level::INFO>(
3092 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
3093 return ipmi::responseInvalidFieldRequest();
3094 }
3095
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303096 ec.clear();
3097 ctx->bus->yield_method_call<>(
3098 ctx->yield, ec, specialModeService, specialModeBasePath,
3099 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
3100 specialModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003101 static_cast<ipmi::DbusVariant>(securityNameSpace::convertForMessage(
3102 static_cast<securityNameSpace::SpecialMode::Modes>(
3103 specialMode.value()))));
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303104
3105 if (ec)
3106 {
3107 phosphor::logging::log<phosphor::logging::level::ERR>(
3108 "ipmiSetSecurityMode: failed to set SpecialMode property",
3109 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3110 return ipmi::responseUnspecifiedError();
3111 }
3112 }
3113#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303114 return ipmi::responseSuccess();
3115}
3116
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003117ipmi::RspType<uint8_t /* restore status */>
3118 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
3119{
3120 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
3121
3122 if (clr != expClr)
3123 {
3124 return ipmi::responseInvalidFieldRequest();
3125 }
3126 constexpr uint8_t cmdStatus = 0;
3127 constexpr uint8_t cmdDefaultRestore = 0xaa;
3128 constexpr uint8_t cmdFullRestore = 0xbb;
3129 constexpr uint8_t cmdFormat = 0xcc;
3130
3131 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3132
3133 switch (cmd)
3134 {
3135 case cmdStatus:
3136 break;
3137 case cmdDefaultRestore:
3138 case cmdFullRestore:
3139 case cmdFormat:
3140 {
3141 // write file to rwfs root
3142 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3143 std::ofstream restoreFile(restoreOpFname);
3144 if (!restoreFile)
3145 {
3146 return ipmi::responseUnspecifiedError();
3147 }
3148 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303149
3150 phosphor::logging::log<phosphor::logging::level::WARNING>(
3151 "Restore to default will be performed on next BMC boot",
3152 phosphor::logging::entry("ACTION=0x%0X", cmd));
3153
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003154 break;
3155 }
3156 default:
3157 return ipmi::responseInvalidFieldRequest();
3158 }
3159
3160 constexpr uint8_t restorePending = 0;
3161 constexpr uint8_t restoreComplete = 1;
3162
3163 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3164 ? restorePending
3165 : restoreComplete;
3166 return ipmi::responseSuccess(restoreStatus);
3167}
3168
Chen Yugang39736d52019-07-12 16:24:33 +08003169ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3170{
3171 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003172 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003173
3174 try
3175 {
3176 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05003177 std::string service = getService(*dbus, oemNmiSourceIntf,
3178 oemNmiSourceObjPath);
3179 Value variant = getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3180 oemNmiSourceIntf,
3181 oemNmiBmcSourceObjPathProp);
Chen Yugang39736d52019-07-12 16:24:33 +08003182
3183 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3184 std::get<std::string>(variant)))
3185 {
3186 case nmi::NMISource::BMCSourceSignal::None:
3187 bmcSource = static_cast<uint8_t>(NmiSource::none);
3188 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003189 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3190 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003191 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003192 case nmi::NMISource::BMCSourceSignal::Watchdog:
3193 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003194 break;
3195 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3196 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3197 break;
3198 case nmi::NMISource::BMCSourceSignal::MemoryError:
3199 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3200 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003201 case nmi::NMISource::BMCSourceSignal::PciBusError:
3202 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003203 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003204 case nmi::NMISource::BMCSourceSignal::PCH:
3205 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003206 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003207 case nmi::NMISource::BMCSourceSignal::Chipset:
3208 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003209 break;
3210 default:
3211 phosphor::logging::log<phosphor::logging::level::ERR>(
3212 "NMI source: invalid property!",
3213 phosphor::logging::entry(
3214 "PROP=%s", std::get<std::string>(variant).c_str()));
3215 return ipmi::responseResponseError();
3216 }
3217 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05003218 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003219 {
3220 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3221 return ipmi::responseResponseError();
3222 }
3223
3224 return ipmi::responseSuccess(bmcSource);
3225}
3226
3227ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3228{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003229 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003230
3231 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3232 nmi::NMISource::BMCSourceSignal::None;
3233
3234 switch (NmiSource(sourceId))
3235 {
3236 case NmiSource::none:
3237 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3238 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003239 case NmiSource::frontPanelButton:
3240 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003241 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003242 case NmiSource::watchdog:
3243 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003244 break;
3245 case NmiSource::chassisCmd:
3246 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3247 break;
3248 case NmiSource::memoryError:
3249 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3250 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003251 case NmiSource::pciBusError:
3252 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003253 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003254 case NmiSource::pch:
3255 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003256 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003257 case NmiSource::chipset:
3258 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003259 break;
3260 default:
3261 phosphor::logging::log<phosphor::logging::level::ERR>(
3262 "NMI source: invalid property!");
3263 return ipmi::responseResponseError();
3264 }
3265
3266 try
3267 {
3268 // keep NMI signal source
3269 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05003270 std::string service = getService(*dbus, oemNmiSourceIntf,
3271 oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003272 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3273 oemNmiBmcSourceObjPathProp,
3274 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003275 // set Enabled property to inform NMI source handling
3276 // to trigger a NMI_OUT BSOD.
3277 // if it's triggered by NMI source property changed,
3278 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3279 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3280 {
3281 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3282 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3283 static_cast<bool>(true));
3284 }
Chen Yugang39736d52019-07-12 16:24:33 +08003285 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003286 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003287 {
3288 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3289 return ipmi::responseResponseError();
3290 }
3291
3292 return ipmi::responseSuccess();
3293}
3294
James Feist63efafa2019-07-24 12:39:21 -07003295namespace dimmOffset
3296{
3297constexpr const char* dimmPower = "DimmPower";
3298constexpr const char* staticCltt = "StaticCltt";
3299constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3300constexpr const char* offsetInterface =
3301 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3302constexpr const char* property = "DimmOffset";
3303
3304}; // namespace dimmOffset
3305
3306ipmi::RspType<>
3307 ipmiOEMSetDimmOffset(uint8_t type,
3308 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3309{
3310 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3311 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3312 {
3313 return ipmi::responseInvalidFieldRequest();
3314 }
3315
3316 if (data.empty())
3317 {
3318 return ipmi::responseInvalidFieldRequest();
3319 }
3320 nlohmann::json json;
3321
3322 std::ifstream jsonStream(dimmOffsetFile);
3323 if (jsonStream.good())
3324 {
3325 json = nlohmann::json::parse(jsonStream, nullptr, false);
3326 if (json.is_discarded())
3327 {
3328 json = nlohmann::json();
3329 }
3330 jsonStream.close();
3331 }
3332
3333 std::string typeName;
3334 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3335 {
3336 typeName = dimmOffset::dimmPower;
3337 }
3338 else
3339 {
3340 typeName = dimmOffset::staticCltt;
3341 }
3342
3343 nlohmann::json& field = json[typeName];
3344
3345 for (const auto& [index, value] : data)
3346 {
3347 field[index] = value;
3348 }
3349
3350 for (nlohmann::json& val : field)
3351 {
3352 if (val == nullptr)
3353 {
3354 val = static_cast<uint8_t>(0);
3355 }
3356 }
3357
3358 std::ofstream output(dimmOffsetFile);
3359 if (!output.good())
3360 {
3361 std::cerr << "Error writing json file\n";
3362 return ipmi::responseResponseError();
3363 }
3364
3365 output << json.dump(4);
3366
3367 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3368 {
3369 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3370
Jason M. Bills0748c692022-09-08 15:34:08 -07003371 ipmi::DbusVariant offsets = field.get<std::vector<uint8_t>>();
James Feist63efafa2019-07-24 12:39:21 -07003372 auto call = bus->new_method_call(
3373 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3374 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3375 try
3376 {
3377 bus->call(call);
3378 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003379 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003380 {
3381 phosphor::logging::log<phosphor::logging::level::ERR>(
3382 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3383 phosphor::logging::entry("ERR=%s", e.what()));
3384 return ipmi::responseResponseError();
3385 }
3386 }
3387
3388 return ipmi::responseSuccess();
3389}
3390
3391ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3392{
James Feist63efafa2019-07-24 12:39:21 -07003393 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3394 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3395 {
3396 return ipmi::responseInvalidFieldRequest();
3397 }
3398
3399 std::ifstream jsonStream(dimmOffsetFile);
3400
3401 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3402 if (json.is_discarded())
3403 {
3404 std::cerr << "File error in " << dimmOffsetFile << "\n";
3405 return ipmi::responseResponseError();
3406 }
3407
3408 std::string typeName;
3409 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3410 {
3411 typeName = dimmOffset::dimmPower;
3412 }
3413 else
3414 {
3415 typeName = dimmOffset::staticCltt;
3416 }
3417
3418 auto it = json.find(typeName);
3419 if (it == json.end())
3420 {
3421 return ipmi::responseInvalidFieldRequest();
3422 }
3423
3424 if (it->size() <= index)
3425 {
3426 return ipmi::responseInvalidFieldRequest();
3427 }
3428
3429 uint8_t resp = it->at(index).get<uint8_t>();
3430 return ipmi::responseSuccess(resp);
3431}
3432
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003433namespace boot_options
3434{
3435
3436using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3437using IpmiValue = uint8_t;
3438constexpr auto ipmiDefault = 0;
3439
3440std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3441 {0x01, Source::Sources::Network},
3442 {0x02, Source::Sources::Disk},
3443 {0x05, Source::Sources::ExternalMedia},
3444 {0x0f, Source::Sources::RemovableMedia},
3445 {ipmiDefault, Source::Sources::Default}};
3446
3447std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003448 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003449
3450std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3451 {Source::Sources::Network, 0x01},
3452 {Source::Sources::Disk, 0x02},
3453 {Source::Sources::ExternalMedia, 0x05},
3454 {Source::Sources::RemovableMedia, 0x0f},
3455 {Source::Sources::Default, ipmiDefault}};
3456
3457std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003458 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003459
3460static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3461static constexpr auto bootSourceIntf =
3462 "xyz.openbmc_project.Control.Boot.Source";
3463static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3464static constexpr auto persistentObjPath =
3465 "/xyz/openbmc_project/control/host0/boot";
3466static constexpr auto oneTimePath =
3467 "/xyz/openbmc_project/control/host0/boot/one_time";
3468static constexpr auto bootSourceProp = "BootSource";
3469static constexpr auto bootModeProp = "BootMode";
3470static constexpr auto oneTimeBootEnableProp = "Enabled";
3471static constexpr auto httpBootMode =
3472 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3473
3474enum class BootOptionParameter : size_t
3475{
3476 setInProgress = 0x0,
3477 bootFlags = 0x5,
3478};
3479static constexpr uint8_t setComplete = 0x0;
3480static constexpr uint8_t setInProgress = 0x1;
3481static uint8_t transferStatus = setComplete;
3482static constexpr uint8_t setParmVersion = 0x01;
3483static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3484static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3485static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3486static constexpr uint8_t httpBoot = 0xd;
3487static constexpr uint8_t bootSourceMask = 0x3c;
3488
3489} // namespace boot_options
3490
3491ipmi::RspType<uint8_t, // version
3492 uint8_t, // param
3493 uint8_t, // data0, dependent on parameter
3494 std::optional<uint8_t> // data1, dependent on parameter
3495 >
Vernon Mauerydcff1502022-09-28 11:12:46 -07003496 ipmiOemGetEfiBootOptions(uint8_t parameter, [[maybe_unused]] uint8_t set,
3497 [[maybe_unused]] uint8_t block)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003498{
3499 using namespace boot_options;
3500 uint8_t bootOption = 0;
3501
3502 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3503 {
3504 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3505 std::nullopt);
3506 }
3507
3508 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3509 {
3510 phosphor::logging::log<phosphor::logging::level::ERR>(
3511 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003512 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003513 }
3514
3515 try
3516 {
3517 auto oneTimeEnabled = false;
3518 // read one time Enabled property
3519 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3520 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3521 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3522 enabledIntf, oneTimeBootEnableProp);
3523 oneTimeEnabled = std::get<bool>(variant);
3524
3525 // get BootSource and BootMode properties
3526 // according to oneTimeEnable
3527 auto bootObjPath = oneTimePath;
3528 if (oneTimeEnabled == false)
3529 {
3530 bootObjPath = persistentObjPath;
3531 }
3532
3533 service = getService(*dbus, bootModeIntf, bootObjPath);
3534 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3535 bootModeProp);
3536
3537 auto bootMode =
3538 Mode::convertModesFromString(std::get<std::string>(variant));
3539
3540 service = getService(*dbus, bootSourceIntf, bootObjPath);
3541 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3542 bootSourceProp);
3543
3544 if (std::get<std::string>(variant) == httpBootMode)
3545 {
3546 bootOption = httpBoot;
3547 }
3548 else
3549 {
3550 auto bootSource = Source::convertSourcesFromString(
3551 std::get<std::string>(variant));
3552 bootOption = sourceDbusToIpmi.at(bootSource);
3553 if (Source::Sources::Default == bootSource)
3554 {
3555 bootOption = modeDbusToIpmi.at(bootMode);
3556 }
3557 }
3558
3559 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3560 : setParmBootFlagsValidPermanent;
3561 bootOption <<= 2; // shift for responseconstexpr
3562 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3563 bootOption);
3564 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003565 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003566 {
3567 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3568 return ipmi::responseResponseError();
3569 }
3570}
3571
3572ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3573 std::optional<uint8_t> bootOption)
3574{
3575 using namespace boot_options;
3576 auto oneTimeEnabled = false;
3577
Mike Jonesbc01d212022-06-16 12:41:33 -07003578 if (bootFlag == 0 && bootParam == 0)
3579 {
3580 phosphor::logging::log<phosphor::logging::level::ERR>(
3581 "Unsupported parameter");
3582 return ipmi::response(ccParameterNotSupported);
3583 }
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003584 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3585 {
3586 if (bootOption)
3587 {
3588 return ipmi::responseReqDataLenInvalid();
3589 }
3590
3591 if (transferStatus == setInProgress)
3592 {
3593 phosphor::logging::log<phosphor::logging::level::ERR>(
3594 "boot option set in progress!");
3595 return ipmi::responseResponseError();
3596 }
3597
3598 transferStatus = bootParam;
3599 return ipmi::responseSuccess();
3600 }
3601
3602 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3603 {
3604 phosphor::logging::log<phosphor::logging::level::ERR>(
3605 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003606 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003607 }
3608
3609 if (!bootOption)
3610 {
3611 return ipmi::responseReqDataLenInvalid();
3612 }
3613
3614 if (((bootOption.value() & bootSourceMask) >> 2) !=
3615 httpBoot) // not http boot, exit
3616 {
3617 phosphor::logging::log<phosphor::logging::level::ERR>(
3618 "wrong boot option parameter!");
3619 return ipmi::responseParmOutOfRange();
3620 }
3621
3622 try
3623 {
3624 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3625 setParmBootFlagsPermanent;
3626
3627 // read one time Enabled property
3628 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3629 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3630 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3631 enabledIntf, oneTimeBootEnableProp);
3632 oneTimeEnabled = std::get<bool>(variant);
3633
3634 /*
3635 * Check if the current boot setting is onetime or permanent, if the
3636 * request in the command is otherwise, then set the "Enabled"
3637 * property in one_time object path to 'True' to indicate onetime
3638 * and 'False' to indicate permanent.
3639 *
3640 * Once the onetime/permanent setting is applied, then the bootMode
3641 * and bootSource is updated for the corresponding object.
3642 */
3643 if (permanent == oneTimeEnabled)
3644 {
3645 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3646 oneTimeBootEnableProp, !permanent);
3647 }
3648
3649 // set BootSource and BootMode properties
3650 // according to oneTimeEnable or persistent
3651 auto bootObjPath = oneTimePath;
3652 if (oneTimeEnabled == false)
3653 {
3654 bootObjPath = persistentObjPath;
3655 }
3656 std::string bootMode =
3657 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3658 std::string bootSource = httpBootMode;
3659
3660 service = getService(*dbus, bootModeIntf, bootObjPath);
3661 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3662 bootMode);
3663
3664 service = getService(*dbus, bootSourceIntf, bootObjPath);
3665 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3666 bootSourceProp, bootSource);
3667 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003668 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003669 {
3670 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3671 return ipmi::responseResponseError();
3672 }
3673
3674 return ipmi::responseSuccess();
3675}
3676
Jason M. Bills0748c692022-09-08 15:34:08 -07003677using BasicVariantType = ipmi::DbusVariant;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003678using PropertyMapType =
3679 boost::container::flat_map<std::string, BasicVariantType>;
3680static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3681 "xyz.openbmc_project.Configuration.PSUPresence"};
Vernon Mauerydcff1502022-09-28 11:12:46 -07003682int getPSUAddress(ipmi::Context::ptr& ctx, uint8_t& bus,
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003683 std::vector<uint64_t>& addrTable)
3684{
3685 boost::system::error_code ec;
3686 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3687 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3688 "/xyz/openbmc_project/object_mapper",
3689 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3690 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3691 if (ec)
3692 {
3693 phosphor::logging::log<phosphor::logging::level::ERR>(
3694 "Failed to set dbus property to cold redundancy");
3695 return -1;
3696 }
3697 for (const auto& object : subtree)
3698 {
3699 std::string pathName = object.first;
3700 for (const auto& serviceIface : object.second)
3701 {
3702 std::string serviceName = serviceIface.first;
3703
3704 ec.clear();
3705 PropertyMapType propMap =
3706 ctx->bus->yield_method_call<PropertyMapType>(
3707 ctx->yield, ec, serviceName, pathName,
3708 "org.freedesktop.DBus.Properties", "GetAll",
3709 "xyz.openbmc_project.Configuration.PSUPresence");
3710 if (ec)
3711 {
3712 phosphor::logging::log<phosphor::logging::level::ERR>(
3713 "Failed to set dbus property to cold redundancy");
3714 return -1;
3715 }
3716 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3717 auto psuAddress =
3718 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3719
3720 if (psuBus == nullptr || psuAddress == nullptr)
3721 {
3722 std::cerr << "error finding necessary "
3723 "entry in configuration\n";
3724 return -1;
3725 }
3726 bus = static_cast<uint8_t>(*psuBus);
3727 addrTable = *psuAddress;
3728 return 0;
3729 }
3730 }
3731 return -1;
3732}
3733
3734static const constexpr uint8_t addrOffset = 8;
3735static const constexpr uint8_t psuRevision = 0xd9;
3736static const constexpr uint8_t defaultPSUBus = 7;
3737// Second Minor, Primary Minor, Major
3738static const constexpr size_t verLen = 3;
Vernon Mauerydcff1502022-09-28 11:12:46 -07003739ipmi::RspType<std::vector<uint8_t>>
3740 ipmiOEMGetPSUVersion(ipmi::Context::ptr& ctx)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003741{
3742 uint8_t bus = defaultPSUBus;
3743 std::vector<uint64_t> addrTable;
3744 std::vector<uint8_t> result;
3745 if (getPSUAddress(ctx, bus, addrTable))
3746 {
3747 std::cerr << "Failed to get PSU bus and address\n";
3748 return ipmi::responseResponseError();
3749 }
3750
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003751 for (const auto& targetAddr : addrTable)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003752 {
3753 std::vector<uint8_t> writeData = {psuRevision};
3754 std::vector<uint8_t> readBuf(verLen);
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003755 uint8_t addr = static_cast<uint8_t>(targetAddr) + addrOffset;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003756 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3757
3758 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3759 if (retI2C != ipmi::ccSuccess)
3760 {
3761 for (size_t idx = 0; idx < verLen; idx++)
3762 {
3763 result.emplace_back(0x00);
3764 }
3765 }
3766 else
3767 {
3768 for (const uint8_t& data : readBuf)
3769 {
3770 result.emplace_back(data);
3771 }
3772 }
3773 }
3774
3775 return ipmi::responseSuccess(result);
3776}
3777
Vernon Mauerydcff1502022-09-28 11:12:46 -07003778std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr& ctx,
srikanta mondal2030d7c2020-05-03 17:25:25 +00003779 const std::string& name)
3780{
3781 Value dbusValue = 0;
3782 std::string serviceName;
3783
3784 boost::system::error_code ec =
3785 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3786
3787 if (ec)
3788 {
3789 phosphor::logging::log<phosphor::logging::level::ERR>(
3790 "Failed to perform Multinode getService.");
3791 return std::nullopt;
3792 }
3793
3794 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3795 multiNodeIntf, name, dbusValue);
3796 if (ec)
3797 {
3798 phosphor::logging::log<phosphor::logging::level::ERR>(
3799 "Failed to perform Multinode get property");
3800 return std::nullopt;
3801 }
3802
3803 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3804 if (!multiNodeVal)
3805 {
3806 phosphor::logging::log<phosphor::logging::level::ERR>(
3807 "getMultiNodeInfoPresence: error to get multinode");
3808 return std::nullopt;
3809 }
3810 return *multiNodeVal;
3811}
3812
3813/** @brief implements OEM get reading command
3814 * @param domain ID
3815 * @param reading Type
3816 * - 00h = platform Power Consumption
3817 * - 01h = inlet Air Temp
3818 * - 02h = icc_TDC from PECI
3819 * @param reserved, write as 0000h
3820 *
3821 * @returns IPMI completion code plus response data
3822 * - response
3823 * - domain ID
3824 * - reading Type
3825 * - 00h = platform Power Consumption
3826 * - 01h = inlet Air Temp
3827 * - 02h = icc_TDC from PECI
3828 * - reading
3829 */
3830ipmi::RspType<uint4_t, // domain ID
3831 uint4_t, // reading Type
3832 uint16_t // reading Value
3833 >
Vernon Mauerydcff1502022-09-28 11:12:46 -07003834 ipmiOEMGetReading(ipmi::Context::ptr& ctx, uint4_t domainId,
srikanta mondal2030d7c2020-05-03 17:25:25 +00003835 uint4_t readingType, uint16_t reserved)
3836{
Vernon Mauerydcff1502022-09-28 11:12:46 -07003837 [[maybe_unused]] constexpr uint8_t platformPower = 0;
srikanta mondal2030d7c2020-05-03 17:25:25 +00003838 constexpr uint8_t inletAirTemp = 1;
3839 constexpr uint8_t iccTdc = 2;
3840
3841 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3842 {
3843 return ipmi::responseInvalidFieldRequest();
3844 }
3845
3846 // This command should run only from multi-node product.
3847 // For all other platforms this command will return invalid.
3848
Patrick Williamsb37abfb2023-05-10 07:50:33 -05003849 std::optional<uint8_t> nodeInfo = getMultiNodeInfoPresence(ctx,
3850 "NodePresence");
srikanta mondal2030d7c2020-05-03 17:25:25 +00003851 if (!nodeInfo || !*nodeInfo)
3852 {
3853 return ipmi::responseInvalidCommand();
3854 }
3855
3856 uint16_t oemReadingValue = 0;
3857 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3858 {
3859 double value = 0;
3860 boost::system::error_code ec = ipmi::getDbusProperty(
3861 ctx, "xyz.openbmc_project.HwmonTempSensor",
3862 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3863 "xyz.openbmc_project.Sensor.Value", "Value", value);
3864 if (ec)
3865 {
3866 phosphor::logging::log<phosphor::logging::level::ERR>(
3867 "Failed to get BMC Get OEM temperature",
3868 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3869 return ipmi::responseUnspecifiedError();
3870 }
3871 // Take the Inlet temperature
3872 oemReadingValue = static_cast<uint16_t>(value);
3873 }
3874 else
3875 {
3876 phosphor::logging::log<phosphor::logging::level::ERR>(
3877 "Currently Get OEM Reading support only for Inlet Air Temp");
3878 return ipmi::responseParmOutOfRange();
3879 }
3880 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3881}
3882
AppaRao Puli28972062019-11-11 02:04:45 +05303883/** @brief implements the maximum size of
3884 * bridgeable messages used between KCS and
3885 * IPMB interfacesget security mode command.
3886 *
3887 * @returns IPMI completion code with following data
3888 * - KCS Buffer Size (In multiples of four bytes)
3889 * - IPMB Buffer Size (In multiples of four bytes)
3890 **/
3891ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3892{
3893 // for now this is hard coded; really this number is dependent on
3894 // the BMC kcs driver as well as the host kcs driver....
3895 // we can't know the latter.
3896 uint8_t kcsMaxBufferSize = 63 / 4;
3897 uint8_t ipmbMaxBufferSize = 128 / 4;
3898
3899 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3900}
3901
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003902ipmi::RspType<std::vector<uint8_t>>
3903 ipmiOEMReadPFRMailbox(ipmi::Context::ptr& ctx, const uint8_t readRegister,
3904 const uint8_t numOfBytes, uint8_t registerIdentifier)
3905{
3906 if (!ipmi::mailbox::i2cConfigLoaded)
3907 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003908 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003909 "Calling PFR Load Configuration Function to Get I2C Bus and Target "
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003910 "Address ");
3911
3912 ipmi::mailbox::loadPfrConfig(ctx, ipmi::mailbox::i2cConfigLoaded);
3913 }
3914
3915 if (!numOfBytes && !readRegister)
3916 {
3917 phosphor::logging::log<phosphor::logging::level::ERR>(
3918 "OEM IPMI command: Read & write count are 0 which is invalid ");
3919 return ipmi::responseInvalidFieldRequest();
3920 }
3921
3922 switch (registerIdentifier)
3923 {
3924 case ipmi::mailbox::registerType::fifoReadRegister:
3925 {
3926 // Check if readRegister is an FIFO read register
Vernon Mauerydcff1502022-09-28 11:12:46 -07003927 if (ipmi::mailbox::readFifoReg.find(readRegister) ==
3928 ipmi::mailbox::readFifoReg.end())
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003929 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003930 phosphor::logging::log<phosphor::logging::level::ERR>(
Vernon Mauerydcff1502022-09-28 11:12:46 -07003931 "OEM IPMI command: Register is not a Read FIFO ");
3932 return ipmi::responseInvalidFieldRequest();
3933 }
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003934
Vernon Mauerydcff1502022-09-28 11:12:46 -07003935 phosphor::logging::log<phosphor::logging::level::ERR>(
3936 "OEM IPMI command: Register is a Read FIFO ");
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003937
Vernon Mauerydcff1502022-09-28 11:12:46 -07003938 ipmi::mailbox::writefifo(ipmi::mailbox::provisioningCommand,
3939 readRegister);
3940 ipmi::mailbox::writefifo(ipmi::mailbox::triggerCommand,
3941 ipmi::mailbox::flushRead);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003942
Vernon Mauerydcff1502022-09-28 11:12:46 -07003943 std::vector<uint8_t> writeData = {ipmi::mailbox::readFifo};
3944 std::vector<uint8_t> readBuf(1);
3945 std::vector<uint8_t> result;
3946
3947 for (int i = 0; i < numOfBytes; i++)
3948 {
3949 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
3950 ipmi::mailbox::targetAddr,
3951 writeData, readBuf);
3952 if (ret != ipmi::ccSuccess)
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003953 {
Vernon Mauerydcff1502022-09-28 11:12:46 -07003954 return ipmi::response(ret);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003955 }
3956
Vernon Mauerydcff1502022-09-28 11:12:46 -07003957 else
3958 {
3959 for (const uint8_t& data : readBuf)
3960 {
3961 result.emplace_back(data);
3962 }
3963 }
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003964 }
Vernon Mauerydcff1502022-09-28 11:12:46 -07003965
3966 return ipmi::responseSuccess(result);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003967 }
3968
3969 case ipmi::mailbox::registerType::singleByteRegister:
3970 {
3971 phosphor::logging::log<phosphor::logging::level::ERR>(
3972 "OEM IPMI command: Register is a Single Byte Register ");
3973
3974 std::vector<uint8_t> writeData = {readRegister};
3975 std::vector<uint8_t> readBuf(numOfBytes);
3976
3977 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003978 ipmi::mailbox::targetAddr,
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003979 writeData, readBuf);
3980 if (ret != ipmi::ccSuccess)
3981 {
3982 return ipmi::response(ret);
3983 }
3984 return ipmi::responseSuccess(readBuf);
3985 }
3986
3987 default:
3988 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003989 phosphor::logging::log<phosphor::logging::level::ERR>(
3990 "OEM IPMI command: Register identifier is not valid.It should "
3991 "be 0 "
3992 "for Single Byte Register and 1 for FIFO Read Register");
3993
3994 return ipmi::responseInvalidFieldRequest();
3995 }
3996 }
3997}
3998
Jason M. Bills64796042018-10-03 16:51:55 -07003999static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004000{
4001 phosphor::logging::log<phosphor::logging::level::INFO>(
4002 "Registering OEM commands");
Vernon Maueryaf652682023-08-04 13:37:21 -07004003 registerHandler(prioOemBase, intel::netFnGeneral,
4004 intel::general::cmdGetBmcVersionString, Privilege::User,
4005 ipmiOEMGetBmcVersionString);
4006
Vernon Mauery98bbf692019-09-16 11:14:59 -07004007 ipmiPrintAndRegister(intel::netFnGeneral,
4008 intel::general::cmdGetChassisIdentifier, NULL,
4009 ipmiOEMGetChassisIdentifier,
4010 PRIVILEGE_USER); // get chassis identifier
4011
4012 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
4013 NULL, ipmiOEMSetSystemGUID,
4014 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07004015
4016 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004017 registerHandler(prioOemBase, intel::netFnGeneral,
4018 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
4019 ipmiOEMDisableBMCSystemReset);
4020
Jason M. Billsb02bf092019-08-15 13:01:56 -07004021 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004022 registerHandler(prioOemBase, intel::netFnGeneral,
4023 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
4024 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07004025
Vernon Mauery98bbf692019-09-16 11:14:59 -07004026 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
4027 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004028
Chen Yugang7a04f3a2019-10-08 11:12:35 +08004029 registerHandler(prioOemBase, intel::netFnGeneral,
4030 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
4031 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004032
Vernon Mauery98bbf692019-09-16 11:14:59 -07004033 ipmiPrintAndRegister(intel::netFnGeneral,
4034 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
4035 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304036
Vernon Mauery98bbf692019-09-16 11:14:59 -07004037 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4038 intel::general::cmdSendEmbeddedFWUpdStatus,
4039 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304040
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05304041 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
4042 Privilege::Admin, ipmiOEMSlotIpmb);
4043
Vernon Mauery98bbf692019-09-16 11:14:59 -07004044 ipmiPrintAndRegister(intel::netFnGeneral,
4045 intel::general::cmdSetPowerRestoreDelay, NULL,
4046 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
4047
4048 ipmiPrintAndRegister(intel::netFnGeneral,
4049 intel::general::cmdGetPowerRestoreDelay, NULL,
4050 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
4051
4052 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4053 intel::general::cmdSetOEMUser2Activation,
4054 Privilege::Callback, ipmiOEMSetUser2Activation);
4055
4056 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4057 intel::general::cmdSetSpecialUserPassword,
4058 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05304059
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004060 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004061 registerHandler(prioOemBase, intel::netFnGeneral,
4062 intel::general::cmdGetProcessorErrConfig, Privilege::User,
4063 ipmiOEMGetProcessorErrConfig);
4064
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004065 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004066 registerHandler(prioOemBase, intel::netFnGeneral,
4067 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
4068 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004069
Vernon Mauery98bbf692019-09-16 11:14:59 -07004070 ipmiPrintAndRegister(intel::netFnGeneral,
4071 intel::general::cmdSetShutdownPolicy, NULL,
4072 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004073
Vernon Mauery98bbf692019-09-16 11:14:59 -07004074 ipmiPrintAndRegister(intel::netFnGeneral,
4075 intel::general::cmdGetShutdownPolicy, NULL,
4076 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004077
anil kumar appanaf945eee2019-09-25 23:29:11 +00004078 registerHandler(prioOemBase, intel::netFnGeneral,
4079 intel::general::cmdSetFanConfig, Privilege::User,
4080 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08004081
Vernon Mauery98bbf692019-09-16 11:14:59 -07004082 registerHandler(prioOemBase, intel::netFnGeneral,
4083 intel::general::cmdGetFanConfig, Privilege::User,
4084 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07004085
Vernon Mauery98bbf692019-09-16 11:14:59 -07004086 registerHandler(prioOemBase, intel::netFnGeneral,
4087 intel::general::cmdGetFanSpeedOffset, Privilege::User,
4088 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004089
Vernon Mauery98bbf692019-09-16 11:14:59 -07004090 registerHandler(prioOemBase, intel::netFnGeneral,
4091 intel::general::cmdSetFanSpeedOffset, Privilege::User,
4092 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004093
Vernon Mauery98bbf692019-09-16 11:14:59 -07004094 registerHandler(prioOemBase, intel::netFnGeneral,
4095 intel::general::cmdSetFscParameter, Privilege::User,
4096 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07004097
Vernon Mauery98bbf692019-09-16 11:14:59 -07004098 registerHandler(prioOemBase, intel::netFnGeneral,
4099 intel::general::cmdGetFscParameter, Privilege::User,
4100 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05304101
Vernon Mauery98bbf692019-09-16 11:14:59 -07004102 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4103 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
4104 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08004105
Vernon Mauery98bbf692019-09-16 11:14:59 -07004106 registerHandler(prioOemBase, intel::netFnGeneral,
4107 intel::general::cmdGetNmiStatus, Privilege::User,
4108 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08004109
Vernon Mauery98bbf692019-09-16 11:14:59 -07004110 registerHandler(prioOemBase, intel::netFnGeneral,
4111 intel::general::cmdSetNmiStatus, Privilege::Operator,
4112 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004113
Vernon Mauery98bbf692019-09-16 11:14:59 -07004114 registerHandler(prioOemBase, intel::netFnGeneral,
4115 intel::general::cmdGetEfiBootOptions, Privilege::User,
4116 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004117
Vernon Mauery98bbf692019-09-16 11:14:59 -07004118 registerHandler(prioOemBase, intel::netFnGeneral,
4119 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
4120 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304121
Vernon Mauery98bbf692019-09-16 11:14:59 -07004122 registerHandler(prioOemBase, intel::netFnGeneral,
4123 intel::general::cmdGetSecurityMode, Privilege::User,
4124 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304125
Vernon Mauery98bbf692019-09-16 11:14:59 -07004126 registerHandler(prioOemBase, intel::netFnGeneral,
4127 intel::general::cmdSetSecurityMode, Privilege::Admin,
4128 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004129
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00004130 registerHandler(prioOemBase, intel::netFnGeneral,
4131 intel::general::cmdGetLEDStatus, Privilege::Admin,
4132 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08004133
Vernon Mauery98bbf692019-09-16 11:14:59 -07004134 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
4135 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
4136 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
4137
4138 registerHandler(prioOemBase, intel::netFnGeneral,
4139 intel::general::cmdSetFaultIndication, Privilege::Operator,
4140 ipmiOEMSetFaultIndication);
4141
4142 registerHandler(prioOemBase, intel::netFnGeneral,
4143 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
4144 ipmiOEMSetCRConfig);
4145
4146 registerHandler(prioOemBase, intel::netFnGeneral,
4147 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
4148 ipmiOEMGetCRConfig);
4149
4150 registerHandler(prioOemBase, intel::netFnGeneral,
4151 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004152 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07004153
Vernon Mauery98bbf692019-09-16 11:14:59 -07004154 registerHandler(prioOemBase, intel::netFnGeneral,
4155 intel::general::cmdSetDimmOffset, Privilege::Operator,
4156 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07004157
Vernon Mauery98bbf692019-09-16 11:14:59 -07004158 registerHandler(prioOemBase, intel::netFnGeneral,
4159 intel::general::cmdGetDimmOffset, Privilege::Operator,
4160 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08004161
Cheng C Yang4e6ee152019-09-25 10:27:44 +08004162 registerHandler(prioOemBase, intel::netFnGeneral,
4163 intel::general::cmdGetPSUVersion, Privilege::User,
4164 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05304165
4166 registerHandler(prioOemBase, intel::netFnGeneral,
4167 intel::general::cmdGetBufferSize, Privilege::User,
4168 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00004169
4170 registerHandler(prioOemBase, intel::netFnGeneral,
4171 intel::general::cmdOEMGetReading, Privilege::User,
4172 ipmiOEMGetReading);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00004173
4174 registerHandler(prioOemBase, intel::netFnApp, intel::app::cmdPFRMailboxRead,
4175 Privilege::Admin, ipmiOEMReadPFRMailbox);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004176}
4177
4178} // namespace ipmi