blob: 390e112185f6da1df6e641422a64bcb6b84deac7 [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);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000273}
274
275} // namespace mailbox
276
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800277// Returns the Chassis Identifier (serial #)
278ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
279 ipmi_request_t request,
280 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700281 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800282 ipmi_context_t context)
283{
284 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700285 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800286 {
Jason M. Bills64796042018-10-03 16:51:55 -0700287 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800288 return IPMI_CC_REQ_DATA_LEN_INVALID;
289 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700290 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
291 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800292 {
Jason M. Bills64796042018-10-03 16:51:55 -0700293 *dataLen = serial.size(); // length will never exceed response length
294 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800295 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700296 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297 return IPMI_CC_OK;
298 }
Jason M. Bills64796042018-10-03 16:51:55 -0700299 *dataLen = 0;
300 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800301}
302
303ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
304 ipmi_request_t request,
305 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700306 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307{
308 static constexpr size_t safeBufferLength = 50;
309 char buf[safeBufferLength] = {0};
310 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
311
Jason M. Bills64796042018-10-03 16:51:55 -0700312 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800313 {
Jason M. Bills64796042018-10-03 16:51:55 -0700314 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 return IPMI_CC_REQ_DATA_LEN_INVALID;
316 }
317
Jason M. Bills64796042018-10-03 16:51:55 -0700318 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800319
320 snprintf(
321 buf, safeBufferLength,
322 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
323 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
324 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
325 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
326 Data->node3, Data->node2, Data->node1);
327 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
328 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800329
330 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
331 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700332 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
333 std::string service = getService(*dbus, intf, objpath);
334 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800335 return IPMI_CC_OK;
336}
337
Jason M. Billsb02bf092019-08-15 13:01:56 -0700338ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
339 uint7_t reserved1)
340{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000341 if (reserved1)
342 {
343 return ipmi::responseInvalidFieldRequest();
344 }
345
Jason M. Billsb02bf092019-08-15 13:01:56 -0700346 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
347
348 try
349 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500350 auto service = ipmi::getService(*busp, bmcResetDisablesIntf,
351 bmcResetDisablesPath);
Jason M. Billsb02bf092019-08-15 13:01:56 -0700352 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
353 bmcResetDisablesIntf, "ResetOnSMI",
354 !disableResetOnSMI);
355 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500356 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700357 {
358 phosphor::logging::log<phosphor::logging::level::ERR>(
359 "Failed to set BMC reset disables",
360 phosphor::logging::entry("EXCEPTION=%s", e.what()));
361 return ipmi::responseUnspecifiedError();
362 }
363
364 return ipmi::responseSuccess();
365}
366
367ipmi::RspType<bool, // disableResetOnSMI
368 uint7_t // reserved
369 >
370 ipmiOEMGetBMCResetDisables()
371{
372 bool disableResetOnSMI = true;
373
374 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
375 try
376 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500377 auto service = ipmi::getService(*busp, bmcResetDisablesIntf,
378 bmcResetDisablesPath);
Jason M. Billsb02bf092019-08-15 13:01:56 -0700379 Value variant =
380 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
381 bmcResetDisablesIntf, "ResetOnSMI");
382 disableResetOnSMI = !std::get<bool>(variant);
383 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500384 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700385 {
386 phosphor::logging::log<phosphor::logging::level::ERR>(
387 "Failed to get BMC reset disables",
388 phosphor::logging::entry("EXCEPTION=%s", e.what()));
389 return ipmi::responseUnspecifiedError();
390 }
391
392 return ipmi::responseSuccess(disableResetOnSMI, 0);
393}
394
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800395ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
396 ipmi_request_t request, ipmi_response_t response,
397 ipmi_data_len_t dataLen, ipmi_context_t context)
398{
399 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
400
Jason M. Bills64796042018-10-03 16:51:55 -0700401 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800402 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800403 *dataLen = 0;
404 return IPMI_CC_REQ_DATA_LEN_INVALID;
405 }
Jason M. Bills64796042018-10-03 16:51:55 -0700406 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000407 for (auto idChar : idString)
408 {
409 if (!std::isprint(static_cast<unsigned char>(idChar)))
410 {
411 phosphor::logging::log<phosphor::logging::level::ERR>(
412 "BIOS ID contains non printable character");
413 return IPMI_CC_INVALID_FIELD_REQUEST;
414 }
415 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800416
Vernon Mauery15419dd2019-05-24 09:40:30 -0700417 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000418 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
419 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800420 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800421 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
422 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700423 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800424 *dataLen = 1;
425 return IPMI_CC_OK;
426}
427
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000428bool getActiveHSCSoftwareVersionInfo(std::string& hscVersion, size_t hscNumber)
429{
430 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
431 try
432 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500433 std::string hsbpObjPath = "/xyz/openbmc_project/software/HSBP_" +
434 std::to_string(hscNumber);
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000435 auto service = getService(*dbus, biosVersionIntf, hsbpObjPath);
436 Value hscVersionValue =
437 getDbusProperty(*dbus, "xyz.openbmc_project.HsbpManager",
438 hsbpObjPath, biosVersionIntf, "Version");
439 hscVersion = std::get<std::string>(hscVersionValue);
440 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500441 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000442 {
443 phosphor::logging::log<phosphor::logging::level::INFO>(
444 "Failed to retrieve HSBP version information",
445 phosphor::logging::entry("HSBP Number=%d", hscNumber));
446 return false;
447 }
448 return true;
449}
450
451bool getHscVerInfo(ipmi::Context::ptr ctx, uint8_t& hsc0Major,
452 uint8_t& hsc0Minor, uint8_t& hsc1Major, uint8_t& hsc1Minor,
453 uint8_t& hsc2Major, uint8_t& hsc2Minor)
454{
455 std::string hscVersion;
456 std::array<uint8_t, 6> hscVersions{0};
457
458 for (size_t hscNumber = 1; hscNumber <= 3; hscNumber++)
459 {
460 if (!getActiveHSCSoftwareVersionInfo(hscVersion, hscNumber))
461 {
462 continue;
463 }
464 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?)");
465 constexpr size_t matchedPhosphor = 4;
466 std::smatch results;
467 // hscVersion = BOOT_VER.FPGA_VER.SECURITY_REVISION (Example: 00.02.01)
468 if (std::regex_match(hscVersion, results, pattern1))
469 {
470 // Major version is FPGA_VER and Minor version is SECURITY_REV
471 if (results.size() == matchedPhosphor)
472 {
473 int index = (hscNumber - 1) * 2;
474 hscVersions[index] =
475 static_cast<uint8_t>(std::stoi(results[2]));
476 hscVersions[index + 1] =
477 static_cast<uint8_t>(std::stoi(results[3]));
478 }
479 }
480 }
481 hsc0Major = hscVersions[0];
482 hsc0Minor = hscVersions[1];
483 hsc1Major = hscVersions[2];
484 hsc1Minor = hscVersions[3];
485 hsc2Major = hscVersions[4];
486 hsc2Minor = hscVersions[5];
487 return true;
488}
489
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530490bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
491 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800492{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800493 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530494 std::string bmcVersion;
495 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800496 {
497 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800498 }
499
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530500 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800501 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800502 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800503 MetaRevision revision = rev.value();
504 bmcMajor = revision.major;
505
506 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
507 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
508 }
509
510 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530511 std::string meVersion;
512 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800513 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800514 return false;
515 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530516 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
517 constexpr size_t matchedPhosphor = 6;
518 std::smatch results;
519 if (std::regex_match(meVersion, results, pattern1))
520 {
521 if (results.size() == matchedPhosphor)
522 {
523 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
Jayaprakash Mutyalad0657022021-08-26 21:18:08 +0000524 meMinor = static_cast<uint8_t>(std::stoi(results[2]) << 4 |
525 std::stoi(results[3]));
AppaRao Puli32825a22020-01-17 15:52:41 +0530526 }
527 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800528 return true;
529}
530
531ipmi::RspType<
532 std::variant<std::string,
533 std::tuple<uint8_t, std::array<uint8_t, 2>,
534 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
535 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
536 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530537 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
538 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530539 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800540{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800541 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
542 {
543 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800544 }
545
546 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800547 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800548 {
549 case OEMDevEntityType::biosId:
550 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530551 // Byte 2&3, Only used with selecting BIOS
552 if (!countToRead || !offset)
553 {
554 return ipmi::responseReqDataLenInvalid();
555 }
556
Vernon Mauery15419dd2019-05-24 09:40:30 -0700557 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500558 std::string service = getService(*dbus, biosVersionIntf,
559 biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800560 try
561 {
Yong Li2742b852019-12-16 14:55:11 +0800562 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000563 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800564 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700565 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530566 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800567 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800568 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800569 }
Jason M. Bills64796042018-10-03 16:51:55 -0700570 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530571 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700572 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530573 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700574 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800575 else
576 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530577 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800578 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800579
580 std::string readBuf = {0};
581 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530582 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800583 (readBuf.begin()));
584 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800585 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500586 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800587 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800588 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800589 }
590 }
591 break;
592
593 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800594 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530595 // Byte 2&3, Only used with selecting BIOS
596 if (countToRead || offset)
597 {
598 return ipmi::responseReqDataLenInvalid();
599 }
600
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800601 constexpr const size_t verLen = 2;
602 constexpr const size_t verTotalLen = 10;
603 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
604 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
605 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
606 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
607 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
608 // data0/1: BMC version number; data6/7: ME version number
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530609 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800610 {
611 return ipmi::responseUnspecifiedError();
612 }
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000613 if (!getHscVerInfo(ctx, hsc0Buf[0], hsc0Buf[1], hsc1Buf[0],
614 hsc1Buf[1], hsc2Buf[0], hsc2Buf[1]))
615 {
616 return ipmi::responseUnspecifiedError();
617 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800618 return ipmi::responseSuccess(
619 std::tuple<
620 uint8_t, std::array<uint8_t, verLen>,
621 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
622 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
623 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
624 }
625 break;
626
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800627 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800628 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530629 // Byte 2&3, Only used with selecting BIOS
630 if (countToRead || offset)
631 {
632 return ipmi::responseReqDataLenInvalid();
633 }
634
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800635 constexpr const size_t sdrLen = 2;
636 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
637 return ipmi::responseSuccess(
638 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
639 readBuf});
640 }
641 break;
642
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800643 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800644 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800645 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800646}
647
648ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
649 ipmi_request_t request, ipmi_response_t response,
650 ipmi_data_len_t dataLen, ipmi_context_t context)
651{
652 if (*dataLen != 0)
653 {
Jason M. Bills64796042018-10-03 16:51:55 -0700654 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800655 return IPMI_CC_REQ_DATA_LEN_INVALID;
656 }
657
658 *dataLen = 1;
659 uint8_t* res = reinterpret_cast<uint8_t*>(response);
660 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
661 // AIC is available so that BIOS will not timeout repeatly which leads to
662 // slow booting.
663 *res = 0; // Byte1=Count of SlotPosition/FruID records.
664 return IPMI_CC_OK;
665}
666
Jason M. Bills64796042018-10-03 16:51:55 -0700667ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
668 ipmi_request_t request,
669 ipmi_response_t response,
670 ipmi_data_len_t dataLen,
671 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800672{
Jason M. Bills64796042018-10-03 16:51:55 -0700673 GetPowerRestoreDelayRes* resp =
674 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
675
676 if (*dataLen != 0)
677 {
678 *dataLen = 0;
679 return IPMI_CC_REQ_DATA_LEN_INVALID;
680 }
681
Vernon Mauery15419dd2019-05-24 09:40:30 -0700682 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500683 std::string service = getService(*dbus, powerRestoreDelayIntf,
684 powerRestoreDelayObjPath);
685 Value variant = getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
686 powerRestoreDelayIntf,
687 powerRestoreDelayProp);
Jason M. Bills64796042018-10-03 16:51:55 -0700688
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300689 uint64_t val = std::get<uint64_t>(variant);
690 val /= 1000000UL;
691 uint16_t delay = val;
Jason M. Bills64796042018-10-03 16:51:55 -0700692 resp->byteLSB = delay;
693 resp->byteMSB = delay >> 8;
694
695 *dataLen = sizeof(GetPowerRestoreDelayRes);
696
697 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800698}
699
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800700static uint8_t bcdToDec(uint8_t val)
701{
702 return ((val / 16 * 10) + (val % 16));
703}
704
705// Allows an update utility or system BIOS to send the status of an embedded
706// firmware update attempt to the BMC. After received, BMC will create a logging
707// record.
708ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
709 uint8_t majorRevision,
710 uint8_t minorRevision,
711 uint32_t auxInfo)
712{
713 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700714 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800715 target = (target & selEvtTargetMask) >> selEvtTargetShift;
716
717 /* make sure the status is 0, 1, or 2 as per the spec */
718 if (status > 2)
719 {
720 return ipmi::response(ipmi::ccInvalidFieldRequest);
721 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700722 /* make sure the target is 0, 1, 2, or 4 as per the spec */
723 if (target > 4 || target == 3)
724 {
725 return ipmi::response(ipmi::ccInvalidFieldRequest);
726 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800727 /*orignal OEM command is to record OEM SEL.
728 But openbmc does not support OEM SEL, so we redirect it to redfish event
729 logging. */
730 std::string buildInfo;
731 std::string action;
732 switch (FWUpdateTarget(target))
733 {
734 case FWUpdateTarget::targetBMC:
735 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700736 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800737 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
738 " BuildID: " + std::to_string(auxInfo);
739 buildInfo += std::to_string(auxInfo);
740 break;
741 case FWUpdateTarget::targetBIOS:
742 firmware = "BIOS";
743 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700744 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800745 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
746 " minor: " +
747 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
748 " ReleaseNumber: " + // ASCII encoded
749 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
750 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
751 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
752 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
753 break;
754 case FWUpdateTarget::targetME:
755 firmware = "ME";
756 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700757 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800758 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
759 " minor2: " +
760 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
761 " build1: " +
762 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
763 " build2: " +
764 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
765 break;
766 case FWUpdateTarget::targetOEMEWS:
767 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700768 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800769 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
770 " BuildID: " + std::to_string(auxInfo);
771 break;
772 }
773
Jason M. Billsdc249272019-04-03 09:58:40 -0700774 static const std::string openBMCMessageRegistryVersion("0.1");
775 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
776
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800777 switch (status)
778 {
779 case 0x0:
780 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700781 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800782 break;
783 case 0x1:
784 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700785 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800786 break;
787 case 0x2:
788 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700789 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800790 break;
791 default:
792 action = "unknown";
793 break;
794 }
795
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500796 std::string firmwareInstanceStr = firmware +
797 " instance: " + std::to_string(instance);
Jason M. Billsdc249272019-04-03 09:58:40 -0700798 std::string message("[firmware update] " + firmwareInstanceStr +
799 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800800
801 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700802 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
803 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
804 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800805 return ipmi::responseSuccess();
806}
807
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530808ipmi::RspType<uint8_t, std::vector<uint8_t>>
809 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
810 uint2_t slotNumber, uint3_t baseBoardSlotNum,
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800811 uint3_t riserSlotNum, uint2_t reserved2, uint8_t targetAddr,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530812 uint8_t netFn, uint8_t cmd,
813 std::optional<std::vector<uint8_t>> writeData)
814{
815 if (reserved1 || reserved2)
816 {
817 return ipmi::responseInvalidFieldRequest();
818 }
819
820 boost::system::error_code ec;
821 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
822 std::vector<uint8_t>>;
823 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
824 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
825 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
826 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800827 static_cast<uint8_t>(baseBoardSlotNum), targetAddr, netFn, cmd,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530828 *writeData);
829 if (ec)
830 {
831 phosphor::logging::log<phosphor::logging::level::ERR>(
832 "Failed to call dbus method SlotIpmbRequest");
833 return ipmi::responseUnspecifiedError();
834 }
835
836 std::vector<uint8_t> dataReceived(0);
837 int status = -1;
838 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
839
840 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
841
842 if (status)
843 {
844 phosphor::logging::log<phosphor::logging::level::ERR>(
845 "Failed to get response from SlotIpmbRequest");
846 return ipmi::responseResponseError();
847 }
848 return ipmi::responseSuccess(cc, dataReceived);
849}
850
Jason M. Bills64796042018-10-03 16:51:55 -0700851ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
852 ipmi_request_t request,
853 ipmi_response_t response,
854 ipmi_data_len_t dataLen,
855 ipmi_context_t context)
856{
857 SetPowerRestoreDelayReq* data =
858 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
859 uint16_t delay = 0;
860
861 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
862 {
863 *dataLen = 0;
864 return IPMI_CC_REQ_DATA_LEN_INVALID;
865 }
866 delay = data->byteMSB;
867 delay = (delay << 8) | data->byteLSB;
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300868 uint64_t val = delay * 1000000;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700869 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500870 std::string service = getService(*dbus, powerRestoreDelayIntf,
871 powerRestoreDelayObjPath);
Vernon Mauery15419dd2019-05-24 09:40:30 -0700872 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300873 powerRestoreDelayIntf, powerRestoreDelayProp, val);
Jason M. Bills64796042018-10-03 16:51:55 -0700874 *dataLen = 0;
875
876 return IPMI_CC_OK;
877}
878
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700879static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700880{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700881 static constexpr const char* cpuPresencePathPrefix =
882 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
883 static constexpr const char* cpuPresenceIntf =
884 "xyz.openbmc_project.Inventory.Item";
885 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
886 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
887 try
Jason M. Bills64796042018-10-03 16:51:55 -0700888 {
Patrick Williamsb37abfb2023-05-10 07:50:33 -0500889 auto service = ipmi::getService(*busp, cpuPresenceIntf,
890 cpuPresencePath);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700891
892 ipmi::Value result = ipmi::getDbusProperty(
893 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
894 return std::get<bool>(result);
895 }
896 catch (const std::exception& e)
897 {
898 phosphor::logging::log<phosphor::logging::level::INFO>(
899 "Cannot find processor presence",
900 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
901 return false;
902 }
903}
904
905ipmi::RspType<bool, // CATERR Reset Enabled
906 bool, // ERR2 Reset Enabled
907 uint6_t, // reserved
908 uint8_t, // reserved, returns 0x3F
909 uint6_t, // CPU1 CATERR Count
910 uint2_t, // CPU1 Status
911 uint6_t, // CPU2 CATERR Count
912 uint2_t, // CPU2 Status
913 uint6_t, // CPU3 CATERR Count
914 uint2_t, // CPU3 Status
915 uint6_t, // CPU4 CATERR Count
916 uint2_t, // CPU4 Status
917 uint8_t // Crashdump Count
918 >
919 ipmiOEMGetProcessorErrConfig()
920{
921 bool resetOnCATERR = false;
922 bool resetOnERR2 = false;
923 uint6_t cpu1CATERRCount = 0;
924 uint6_t cpu2CATERRCount = 0;
925 uint6_t cpu3CATERRCount = 0;
926 uint6_t cpu4CATERRCount = 0;
927 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700928 uint2_t cpu1Status = cpuPresent("CPU_1")
929 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
930 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
931 uint2_t cpu2Status = cpuPresent("CPU_2")
932 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
933 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
934 uint2_t cpu3Status = cpuPresent("CPU_3")
935 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
936 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
937 uint2_t cpu4Status = cpuPresent("CPU_4")
938 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
939 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700940
941 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
942 try
943 {
944 auto service = ipmi::getService(*busp, processorErrConfigIntf,
945 processorErrConfigObjPath);
946
947 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
948 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
949 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
950 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
951 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
952 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
953 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
954 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
955 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
956 }
957 catch (const std::exception& e)
958 {
959 phosphor::logging::log<phosphor::logging::level::ERR>(
960 "Failed to fetch processor error config",
961 phosphor::logging::entry("ERROR=%s", e.what()));
962 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700963 }
964
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700965 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
966 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
967 cpu2Status, cpu3CATERRCount, cpu3Status,
968 cpu4CATERRCount, cpu4Status, crashdumpCount);
969}
Jason M. Bills64796042018-10-03 16:51:55 -0700970
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700971ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
972 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
973 std::optional<bool> clearCPUErrorCount,
974 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
975{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000976 if (reserved1 || reserved2)
977 {
978 return ipmi::responseInvalidFieldRequest();
979 }
980
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700981 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700982
983 try
984 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000985 if (reserved3.value_or(0))
986 {
987 return ipmi::responseInvalidFieldRequest();
988 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700989 auto service = ipmi::getService(*busp, processorErrConfigIntf,
990 processorErrConfigObjPath);
991 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
992 processorErrConfigIntf, "ResetOnCATERR",
993 resetOnCATERR);
994 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
995 processorErrConfigIntf, "ResetOnERR2",
996 resetOnERR2);
997 if (clearCPUErrorCount.value_or(false))
998 {
999 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001000 processorErrConfigIntf, "ErrorCountCPU1",
1001 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001002 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001003 processorErrConfigIntf, "ErrorCountCPU2",
1004 static_cast<uint8_t>(0));
1005 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1006 processorErrConfigIntf, "ErrorCountCPU3",
1007 static_cast<uint8_t>(0));
1008 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1009 processorErrConfigIntf, "ErrorCountCPU4",
1010 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001011 }
1012 if (clearCrashdumpCount.value_or(false))
1013 {
1014 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001015 processorErrConfigIntf, "CrashdumpCount",
1016 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001017 }
Jason M. Bills64796042018-10-03 16:51:55 -07001018 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001019 catch (const std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -07001020 {
Kuiying Wangbc546672018-11-23 15:41:05 +08001021 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001022 "Failed to set processor error config",
1023 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1024 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -07001025 }
1026
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001027 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -07001028}
1029
Yong Li703922d2018-11-06 13:25:31 +08001030ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1031 ipmi_request_t request,
1032 ipmi_response_t response,
1033 ipmi_data_len_t dataLen,
1034 ipmi_context_t context)
1035{
1036 GetOEMShutdownPolicyRes* resp =
1037 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
1038
1039 if (*dataLen != 0)
1040 {
1041 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +08001042 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +08001043 *dataLen = 0;
1044 return IPMI_CC_REQ_DATA_LEN_INVALID;
1045 }
1046
1047 *dataLen = 0;
1048
1049 try
1050 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001051 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001052 std::string service = getService(*dbus, oemShutdownPolicyIntf,
1053 oemShutdownPolicyObjPath);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001054 Value variant = getDbusProperty(
1055 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
1056 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +08001057
1058 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1059 convertPolicyFromString(std::get<std::string>(variant)) ==
1060 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1061 NoShutdownOnOCOT)
1062 {
1063 resp->policy = 0;
1064 }
1065 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1066 convertPolicyFromString(std::get<std::string>(variant)) ==
1067 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1068 Policy::ShutdownOnOCOT)
1069 {
1070 resp->policy = 1;
1071 }
1072 else
1073 {
1074 phosphor::logging::log<phosphor::logging::level::ERR>(
1075 "oem_set_shutdown_policy: invalid property!",
1076 phosphor::logging::entry(
1077 "PROP=%s", std::get<std::string>(variant).c_str()));
1078 return IPMI_CC_UNSPECIFIED_ERROR;
1079 }
Yong Li703922d2018-11-06 13:25:31 +08001080 // TODO needs to check if it is multi-node products,
1081 // policy is only supported on node 3/4
1082 resp->policySupport = shutdownPolicySupported;
1083 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001084 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001085 {
1086 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1087 return IPMI_CC_UNSPECIFIED_ERROR;
1088 }
1089
1090 *dataLen = sizeof(GetOEMShutdownPolicyRes);
1091 return IPMI_CC_OK;
1092}
1093
1094ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1095 ipmi_request_t request,
1096 ipmi_response_t response,
1097 ipmi_data_len_t dataLen,
1098 ipmi_context_t context)
1099{
1100 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +08001101 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
1102 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1103 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +08001104
1105 // TODO needs to check if it is multi-node products,
1106 // policy is only supported on node 3/4
1107 if (*dataLen != 1)
1108 {
1109 phosphor::logging::log<phosphor::logging::level::ERR>(
1110 "oem_set_shutdown_policy: invalid input len!");
1111 *dataLen = 0;
1112 return IPMI_CC_REQ_DATA_LEN_INVALID;
1113 }
1114
1115 *dataLen = 0;
1116 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
1117 {
1118 phosphor::logging::log<phosphor::logging::level::ERR>(
1119 "oem_set_shutdown_policy: invalid input!");
1120 return IPMI_CC_INVALID_FIELD_REQUEST;
1121 }
1122
Yong Li0669d192019-05-06 14:01:46 +08001123 if (*req == noShutdownOnOCOT)
1124 {
1125 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1126 Policy::NoShutdownOnOCOT;
1127 }
1128 else
1129 {
1130 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1131 Policy::ShutdownOnOCOT;
1132 }
1133
Yong Li703922d2018-11-06 13:25:31 +08001134 try
1135 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001136 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001137 std::string service = getService(*dbus, oemShutdownPolicyIntf,
1138 oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +08001139 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001140 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +08001141 oemShutdownPolicyObjPathProp,
1142 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +08001143 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001144 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001145 {
1146 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1147 return IPMI_CC_UNSPECIFIED_ERROR;
1148 }
1149
1150 return IPMI_CC_OK;
1151}
1152
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301153/** @brief implementation for check the DHCP or not in IPv4
1154 * @param[in] Channel - Channel number
1155 * @returns true or false.
1156 */
1157static bool isDHCPEnabled(uint8_t Channel)
1158{
1159 try
1160 {
1161 auto ethdevice = getChannelName(Channel);
1162 if (ethdevice.empty())
1163 {
1164 return false;
1165 }
1166 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001167 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001168 auto ethernetObj = getDbusObject(*dbus, networkIPIntf, networkRoot,
1169 ethIP);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001170 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301171 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001172 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301173 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1174 {
1175 return true;
1176 }
1177 else
1178 {
1179 return false;
1180 }
1181 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001182 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301183 {
1184 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1185 return true;
1186 }
1187}
1188
1189/** @brief implementes for check the DHCP or not in IPv6
1190 * @param[in] Channel - Channel number
1191 * @returns true or false.
1192 */
1193static bool isDHCPIPv6Enabled(uint8_t Channel)
1194{
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301195 try
1196 {
1197 auto ethdevice = getChannelName(Channel);
1198 if (ethdevice.empty())
1199 {
1200 return false;
1201 }
1202 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001203 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001204 auto objectInfo = getDbusObject(*dbus, networkIPIntf, networkRoot,
1205 ethIP);
Vernon Mauery15419dd2019-05-24 09:40:30 -07001206 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301207 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001208 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301209 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1210 {
1211 return true;
1212 }
1213 else
1214 {
1215 return false;
1216 }
1217 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001218 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301219 {
1220 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1221 return true;
1222 }
1223}
1224
1225/** @brief implementes the creating of default new user
1226 * @param[in] userName - new username in 16 bytes.
1227 * @param[in] userPassword - new password in 20 bytes
1228 * @returns ipmi completion code.
1229 */
1230ipmi::RspType<> ipmiOEMSetUser2Activation(
1231 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001232 const SecureBuffer& userPassword)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301233{
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001234 if (userPassword.size() != ipmi::maxIpmi20PasswordSize)
1235 {
1236 return ipmi::responseReqDataLenInvalid();
1237 }
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301238 bool userState = false;
1239 // Check for System Interface not exist and LAN should be static
1240 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1241 {
Manish Baing440f62b2021-07-15 22:00:37 +00001242 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301243 try
1244 {
1245 getChannelInfo(channel, chInfo);
1246 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001247 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301248 {
1249 phosphor::logging::log<phosphor::logging::level::ERR>(
1250 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1251 phosphor::logging::entry("MSG: %s", e.description()));
1252 return ipmi::response(ipmi::ccUnspecifiedError);
1253 }
1254 if (chInfo.mediumType ==
1255 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1256 {
1257 phosphor::logging::log<phosphor::logging::level::ERR>(
1258 "ipmiOEMSetUser2Activation: system interface exist .");
1259 return ipmi::response(ipmi::ccCommandNotAvailable);
1260 }
1261 else
1262 {
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301263 if (chInfo.mediumType ==
1264 static_cast<uint8_t>(EChannelMediumType::lan8032))
1265 {
1266 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1267 {
1268 phosphor::logging::log<phosphor::logging::level::ERR>(
1269 "ipmiOEMSetUser2Activation: DHCP enabled .");
1270 return ipmi::response(ipmi::ccCommandNotAvailable);
1271 }
1272 }
1273 }
1274 }
1275 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1276 if (ipmi::ccSuccess ==
1277 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1278 {
1279 if (enabledUsers > 1)
1280 {
1281 phosphor::logging::log<phosphor::logging::level::ERR>(
1282 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1283 return ipmi::response(ipmi::ccCommandNotAvailable);
1284 }
1285 // Check the user 2 is enabled or not
1286 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1287 if (userState == true)
1288 {
1289 phosphor::logging::log<phosphor::logging::level::ERR>(
1290 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1291 return ipmi::response(ipmi::ccCommandNotAvailable);
1292 }
1293 }
1294 else
1295 {
1296 return ipmi::response(ipmi::ccUnspecifiedError);
1297 }
1298
1299#if BYTE_ORDER == LITTLE_ENDIAN
1300 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1301#endif
1302#if BYTE_ORDER == BIG_ENDIAN
1303 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1304#endif
1305
Vernon Mauery037cabd2020-05-14 12:16:01 -07001306 // ipmiUserSetUserName correctly handles char*, possibly non-null
1307 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001308 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1309 sizeof(userName));
1310 const std::string userNameRaw(
1311 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001312
Vernon Mauery037cabd2020-05-14 12:16:01 -07001313 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301314 {
1315 if (ipmi::ccSuccess ==
1316 ipmiUserSetUserPassword(
1317 ipmiDefaultUserId,
1318 reinterpret_cast<const char*>(userPassword.data())))
1319 {
1320 if (ipmi::ccSuccess ==
1321 ipmiUserSetPrivilegeAccess(
1322 ipmiDefaultUserId,
1323 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1324 privAccess, true))
1325 {
1326 phosphor::logging::log<phosphor::logging::level::INFO>(
1327 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001328
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301329 return ipmi::responseSuccess();
1330 }
1331 }
1332 // we need to delete the default user id which added in this command as
1333 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001334 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301335 phosphor::logging::log<phosphor::logging::level::ERR>(
1336 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1337 }
1338 else
1339 {
1340 phosphor::logging::log<phosphor::logging::level::ERR>(
1341 "ipmiOEMSetUser2Activation: Setting username failed.");
1342 }
1343
1344 return ipmi::response(ipmi::ccCommandNotAvailable);
1345}
1346
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301347/** @brief implementes executing the linux command
1348 * @param[in] linux command
1349 * @returns status
1350 */
1351
1352static uint8_t executeCmd(const char* path)
1353{
1354 boost::process::child execProg(path);
1355 execProg.wait();
1356
1357 int retCode = execProg.exit_code();
1358 if (retCode)
1359 {
1360 return ipmi::ccUnspecifiedError;
1361 }
1362 return ipmi::ccSuccess;
1363}
1364
1365/** @brief implementes ASD Security event logging
1366 * @param[in] Event message string
1367 * @param[in] Event Severity
1368 * @returns status
1369 */
1370
1371static void atScaleDebugEventlog(std::string msg, int severity)
1372{
1373 std::string eventStr = "OpenBMC.0.1." + msg;
1374 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1375 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1376 eventStr.c_str(), NULL);
1377}
1378
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301379/** @brief implementes setting password for special user
1380 * @param[in] specialUserIndex
1381 * @param[in] userPassword - new password in 20 bytes
1382 * @returns ipmi completion code.
1383 */
1384ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1385 uint8_t specialUserIndex,
1386 std::vector<uint8_t> userPassword)
1387{
1388 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301389 ipmi_ret_t status = ipmi::ccSuccess;
1390
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301391 try
1392 {
1393 getChannelInfo(ctx->channel, chInfo);
1394 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001395 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301396 {
1397 phosphor::logging::log<phosphor::logging::level::ERR>(
1398 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1399 phosphor::logging::entry("MSG: %s", e.description()));
1400 return ipmi::responseUnspecifiedError();
1401 }
1402 if (chInfo.mediumType !=
1403 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1404 {
1405 phosphor::logging::log<phosphor::logging::level::ERR>(
1406 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1407 "interface");
1408 return ipmi::responseCommandNotAvailable();
1409 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301410
1411 // 0 for root user and 1 for AtScaleDebug is allowed
1412 if (specialUserIndex >
1413 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301414 {
1415 phosphor::logging::log<phosphor::logging::level::ERR>(
1416 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1417 return ipmi::responseParmOutOfRange();
1418 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301419 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301420 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301421 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001422 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301423 if (userPassword.size() < minPasswordSizeRequired ||
1424 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1425 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001426 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301427 return ipmi::responseReqDataLenInvalid();
1428 }
1429 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1430 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001431 // Clear sensitive data
1432 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301433 if (specialUserIndex ==
1434 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1435 {
1436 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1437
1438 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1439 }
1440 else
1441 {
1442 status = ipmiSetSpecialUserPassword("root", passwd);
1443 }
1444 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301445 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301446 else
1447 {
1448 if (specialUserIndex ==
1449 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1450 {
1451 status = executeCmd("passwd -d root");
1452 }
1453 else
1454 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301455 status = executeCmd("passwd -d asdbg");
1456
1457 if (status == 0)
1458 {
1459 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1460 LOG_INFO);
1461 }
1462 }
1463 return ipmi::response(status);
1464 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301465}
1466
Kuiying Wang45f04982018-12-26 09:23:08 +08001467namespace ledAction
1468{
1469using namespace sdbusplus::xyz::openbmc_project::Led::server;
1470std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001471 {Physical::Action::Off, 0},
1472 {Physical::Action::On, 2},
1473 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001474
1475std::map<uint8_t, std::string> offsetObjPath = {
1476 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1477
1478} // namespace ledAction
1479
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001480int8_t getLEDState(sdbusplus::bus_t& bus, const std::string& intf,
Kuiying Wang45f04982018-12-26 09:23:08 +08001481 const std::string& objPath, uint8_t& state)
1482{
1483 try
1484 {
1485 std::string service = getService(bus, intf, objPath);
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001486 Value stateValue = getDbusProperty(bus, service, objPath, intf,
1487 "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001488 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001489 state = ledAction::actionDbusToIpmi.at(
1490 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1491 convertActionFromString(strState));
1492 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001493 catch (const sdbusplus::exception_t& e)
Kuiying Wang45f04982018-12-26 09:23:08 +08001494 {
1495 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1496 return -1;
1497 }
1498 return 0;
1499}
1500
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001501ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001502{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001503 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001504 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001505 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001506 for (auto it = ledAction::offsetObjPath.begin();
1507 it != ledAction::offsetObjPath.end(); ++it)
1508 {
1509 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001510 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001511 {
1512 phosphor::logging::log<phosphor::logging::level::ERR>(
1513 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001514 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001515 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001516 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001517 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001518 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001519}
1520
Yong Li23737fe2019-02-19 08:49:55 +08001521ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1522 ipmi_request_t request,
1523 ipmi_response_t response,
1524 ipmi_data_len_t dataLen,
1525 ipmi_context_t context)
1526{
1527 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1528 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1529
1530 if (*dataLen == 0)
1531 {
1532 phosphor::logging::log<phosphor::logging::level::ERR>(
1533 "CfgHostSerial: invalid input len!",
1534 phosphor::logging::entry("LEN=%d", *dataLen));
1535 return IPMI_CC_REQ_DATA_LEN_INVALID;
1536 }
1537
1538 switch (req->command)
1539 {
1540 case getHostSerialCfgCmd:
1541 {
1542 if (*dataLen != 1)
1543 {
1544 phosphor::logging::log<phosphor::logging::level::ERR>(
1545 "CfgHostSerial: invalid input len!");
1546 *dataLen = 0;
1547 return IPMI_CC_REQ_DATA_LEN_INVALID;
1548 }
1549
1550 *dataLen = 0;
1551
1552 boost::process::ipstream is;
1553 std::vector<std::string> data;
1554 std::string line;
1555 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1556 boost::process::std_out > is);
1557
1558 while (c1.running() && std::getline(is, line) && !line.empty())
1559 {
1560 data.push_back(line);
1561 }
1562
1563 c1.wait();
1564 if (c1.exit_code())
1565 {
1566 phosphor::logging::log<phosphor::logging::level::ERR>(
1567 "CfgHostSerial:: error on execute",
1568 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1569 // Using the default value
1570 *resp = 0;
1571 }
1572 else
1573 {
1574 if (data.size() != 1)
1575 {
1576 phosphor::logging::log<phosphor::logging::level::ERR>(
1577 "CfgHostSerial:: error on read env");
1578 return IPMI_CC_UNSPECIFIED_ERROR;
1579 }
1580 try
1581 {
1582 unsigned long tmp = std::stoul(data[0]);
1583 if (tmp > std::numeric_limits<uint8_t>::max())
1584 {
1585 throw std::out_of_range("Out of range");
1586 }
1587 *resp = static_cast<uint8_t>(tmp);
1588 }
1589 catch (const std::invalid_argument& e)
1590 {
1591 phosphor::logging::log<phosphor::logging::level::ERR>(
1592 "invalid config ",
1593 phosphor::logging::entry("ERR=%s", e.what()));
1594 return IPMI_CC_UNSPECIFIED_ERROR;
1595 }
1596 catch (const std::out_of_range& e)
1597 {
1598 phosphor::logging::log<phosphor::logging::level::ERR>(
1599 "out_of_range config ",
1600 phosphor::logging::entry("ERR=%s", e.what()));
1601 return IPMI_CC_UNSPECIFIED_ERROR;
1602 }
1603 }
1604
1605 *dataLen = 1;
1606 break;
1607 }
1608 case setHostSerialCfgCmd:
1609 {
1610 if (*dataLen != sizeof(CfgHostSerialReq))
1611 {
1612 phosphor::logging::log<phosphor::logging::level::ERR>(
1613 "CfgHostSerial: invalid input len!");
1614 *dataLen = 0;
1615 return IPMI_CC_REQ_DATA_LEN_INVALID;
1616 }
1617
1618 *dataLen = 0;
1619
1620 if (req->parameter > HostSerialCfgParamMax)
1621 {
1622 phosphor::logging::log<phosphor::logging::level::ERR>(
1623 "CfgHostSerial: invalid input!");
1624 return IPMI_CC_INVALID_FIELD_REQUEST;
1625 }
1626
1627 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1628 std::to_string(req->parameter));
1629
1630 c1.wait();
1631 if (c1.exit_code())
1632 {
1633 phosphor::logging::log<phosphor::logging::level::ERR>(
1634 "CfgHostSerial:: error on execute",
1635 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1636 return IPMI_CC_UNSPECIFIED_ERROR;
1637 }
1638 break;
1639 }
1640 default:
1641 phosphor::logging::log<phosphor::logging::level::ERR>(
1642 "CfgHostSerial: invalid input!");
1643 *dataLen = 0;
1644 return IPMI_CC_INVALID_FIELD_REQUEST;
1645 }
1646
1647 return IPMI_CC_OK;
1648}
1649
James Feist91244a62019-02-19 15:04:54 -08001650constexpr const char* thermalModeInterface =
1651 "xyz.openbmc_project.Control.ThermalMode";
1652constexpr const char* thermalModePath =
1653 "/xyz/openbmc_project/control/thermal_mode";
1654
1655bool getFanProfileInterface(
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001656 sdbusplus::bus_t& bus,
Jason M. Bills0748c692022-09-08 15:34:08 -07001657 boost::container::flat_map<std::string, ipmi::DbusVariant>& resp)
James Feist91244a62019-02-19 15:04:54 -08001658{
1659 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1660 "GetAll");
1661 call.append(thermalModeInterface);
1662 try
1663 {
1664 auto data = bus.call(call);
1665 data.read(resp);
1666 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001667 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001668 {
1669 phosphor::logging::log<phosphor::logging::level::ERR>(
1670 "getFanProfileInterface: can't get thermal mode!",
1671 phosphor::logging::entry("ERR=%s", e.what()));
1672 return false;
1673 }
1674 return true;
1675}
1676
anil kumar appanaf945eee2019-09-25 23:29:11 +00001677/**@brief implements the OEM set fan config.
1678 * @param selectedFanProfile - fan profile to enable
1679 * @param reserved1
1680 * @param performanceMode - Performance/Acoustic mode
1681 * @param reserved2
1682 * @param setPerformanceMode - set Performance/Acoustic mode
1683 * @param setFanProfile - set fan profile
1684 *
1685 * @return IPMI completion code.
1686 **/
1687ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1688
1689 uint2_t reserved1, bool performanceMode,
1690 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301691 bool setFanProfile,
1692 std::optional<uint8_t> dimmGroupId,
1693 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001694{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001695 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001696 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001697 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001698 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301699
1700 if (dimmGroupId)
1701 {
1702 if (*dimmGroupId >= maxCPUNum)
1703 {
1704 return ipmi::responseInvalidFieldRequest();
1705 }
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001706 if (!cpuPresent("cpu" + std::to_string(*dimmGroupId)))
Joshi-Mansi619186d2020-01-27 19:16:03 +05301707 {
1708 return ipmi::responseInvalidFieldRequest();
1709 }
1710 }
1711
James Feist91244a62019-02-19 15:04:54 -08001712 // todo: tell bios to only send first 2 bytes
Jason M. Bills0748c692022-09-08 15:34:08 -07001713 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001714 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1715 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001716 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001717 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001718 }
1719
1720 std::vector<std::string>* supported =
1721 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1722 if (supported == nullptr)
1723 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001724 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001725 }
1726 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001727 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001728 {
James Feist91244a62019-02-19 15:04:54 -08001729 if (performanceMode)
1730 {
James Feist91244a62019-02-19 15:04:54 -08001731 if (std::find(supported->begin(), supported->end(),
1732 "Performance") != supported->end())
1733 {
1734 mode = "Performance";
1735 }
1736 }
1737 else
1738 {
James Feist91244a62019-02-19 15:04:54 -08001739 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1740 supported->end())
1741 {
1742 mode = "Acoustic";
1743 }
1744 }
1745 if (mode.empty())
1746 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001747 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001748 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001749
1750 try
1751 {
1752 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1753 thermalModeInterface, "Current", mode);
1754 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001755 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001756 {
1757 phosphor::logging::log<phosphor::logging::level::ERR>(
1758 "ipmiOEMSetFanConfig: can't set thermal mode!",
1759 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1760 return ipmi::responseResponseError();
1761 }
James Feist91244a62019-02-19 15:04:54 -08001762 }
1763
anil kumar appanaf945eee2019-09-25 23:29:11 +00001764 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001765}
1766
James Feist5b693632019-07-09 09:06:09 -07001767ipmi::RspType<uint8_t, // profile support map
1768 uint8_t, // fan control profile enable
1769 uint8_t, // flags
1770 uint32_t // dimm presence bit map
1771 >
1772 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001773{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301774 if (dimmGroupId >= maxCPUNum)
1775 {
1776 return ipmi::responseInvalidFieldRequest();
1777 }
1778
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001779 bool cpuStatus = cpuPresent("cpu" + std::to_string(dimmGroupId));
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301780
1781 if (!cpuStatus)
1782 {
1783 return ipmi::responseInvalidFieldRequest();
1784 }
1785
Jason M. Bills0748c692022-09-08 15:34:08 -07001786 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
James Feist91244a62019-02-19 15:04:54 -08001787
Vernon Mauery15419dd2019-05-24 09:40:30 -07001788 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1789 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001790 {
James Feist5b693632019-07-09 09:06:09 -07001791 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001792 }
1793
1794 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1795
1796 if (current == nullptr)
1797 {
1798 phosphor::logging::log<phosphor::logging::level::ERR>(
1799 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001800 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001801 }
1802 bool performance = (*current == "Performance");
1803
James Feist5b693632019-07-09 09:06:09 -07001804 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001805 if (performance)
1806 {
James Feist5b693632019-07-09 09:06:09 -07001807 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001808 }
1809
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001810 constexpr uint8_t fanControlDefaultProfile = 0x80;
1811 constexpr uint8_t fanControlProfileState = 0x00;
1812 constexpr uint32_t dimmPresenceBitmap = 0x00;
1813
1814 return ipmi::responseSuccess(fanControlDefaultProfile,
1815 fanControlProfileState, flags,
1816 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001817}
James Feist5f957ca2019-03-14 15:33:55 -07001818constexpr const char* cfmLimitSettingPath =
1819 "/xyz/openbmc_project/control/cfm_limit";
1820constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001821constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001822constexpr const size_t legacyPCHSensorNumber = 0x22;
1823constexpr const char* exitAirPathName = "Exit_Air";
1824constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001825constexpr const char* pidConfigurationIface =
1826 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001827
James Feist09f6b602019-08-08 11:30:03 -07001828static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001829{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001830 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001831 auto method = dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1832 "/xyz/openbmc_project/object_mapper",
1833 "xyz.openbmc_project.ObjectMapper",
1834 "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001835
James Feistacc8a4e2019-04-02 14:23:57 -07001836 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001837 std::string path;
1838 GetSubTreeType resp;
1839 try
1840 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001841 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001842 reply.read(resp);
1843 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001844 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001845 {
1846 phosphor::logging::log<phosphor::logging::level::ERR>(
1847 "ipmiOEMGetFscParameter: mapper error");
1848 };
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001849 auto config = std::find_if(resp.begin(), resp.end(),
1850 [&name](const auto& pair) {
1851 return pair.first.find(name) != std::string::npos;
1852 });
James Feistfaa4f222019-03-21 16:21:55 -07001853 if (config != resp.end())
1854 {
1855 path = std::move(config->first);
1856 }
1857 return path;
1858}
James Feist5f957ca2019-03-14 15:33:55 -07001859
James Feistacc8a4e2019-04-02 14:23:57 -07001860// flat map to make alphabetical
1861static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1862{
1863 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001864 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05001865 auto method = dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1866 "/xyz/openbmc_project/object_mapper",
1867 "xyz.openbmc_project.ObjectMapper",
1868 "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001869
1870 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1871 GetSubTreeType resp;
1872
1873 try
1874 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001875 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001876 reply.read(resp);
1877 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001878 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001879 {
1880 phosphor::logging::log<phosphor::logging::level::ERR>(
1881 "getFanConfigPaths: mapper error");
1882 };
1883 for (const auto& [path, objects] : resp)
1884 {
1885 if (objects.empty())
1886 {
1887 continue; // should be impossible
1888 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001889
1890 try
1891 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001892 ret.emplace(path,
1893 getAllDbusProperties(*dbus, objects[0].first, path,
1894 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001895 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001896 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001897 {
1898 phosphor::logging::log<phosphor::logging::level::ERR>(
1899 "getPidConfigs: can't get DbusProperties!",
1900 phosphor::logging::entry("ERR=%s", e.what()));
1901 }
James Feistacc8a4e2019-04-02 14:23:57 -07001902 }
1903 return ret;
1904}
1905
1906ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1907{
1908 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1909 if (data.empty())
1910 {
1911 return ipmi::responseResponseError();
1912 }
1913 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1914 for (const auto& [_, pid] : data)
1915 {
1916 auto findClass = pid.find("Class");
1917 if (findClass == pid.end())
1918 {
1919 phosphor::logging::log<phosphor::logging::level::ERR>(
1920 "ipmiOEMGetFscParameter: found illegal pid "
1921 "configurations");
1922 return ipmi::responseResponseError();
1923 }
1924 std::string type = std::get<std::string>(findClass->second);
1925 if (type == "fan")
1926 {
1927 auto findOutLimit = pid.find("OutLimitMin");
1928 if (findOutLimit == pid.end())
1929 {
1930 phosphor::logging::log<phosphor::logging::level::ERR>(
1931 "ipmiOEMGetFscParameter: found illegal pid "
1932 "configurations");
1933 return ipmi::responseResponseError();
1934 }
1935 // get the min out of all the offsets
1936 minOffset = std::min(
1937 minOffset,
1938 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1939 }
1940 }
1941 if (minOffset == std::numeric_limits<uint8_t>::max())
1942 {
1943 phosphor::logging::log<phosphor::logging::level::ERR>(
1944 "ipmiOEMGetFscParameter: found no fan configurations!");
1945 return ipmi::responseResponseError();
1946 }
1947
1948 return ipmi::responseSuccess(minOffset);
1949}
1950
1951ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1952{
Manish Baingbaa579f2021-10-08 22:30:32 +00001953 constexpr uint8_t maxFanSpeedOffset = 100;
1954 if (offset > maxFanSpeedOffset)
1955 {
1956 phosphor::logging::log<phosphor::logging::level::ERR>(
1957 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1958 return ipmi::responseInvalidFieldRequest();
1959 }
James Feistacc8a4e2019-04-02 14:23:57 -07001960 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1961 if (data.empty())
1962 {
James Feistacc8a4e2019-04-02 14:23:57 -07001963 phosphor::logging::log<phosphor::logging::level::ERR>(
1964 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1965 return ipmi::responseResponseError();
1966 }
1967
Vernon Mauery15419dd2019-05-24 09:40:30 -07001968 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001969 bool found = false;
1970 for (const auto& [path, pid] : data)
1971 {
1972 auto findClass = pid.find("Class");
1973 if (findClass == pid.end())
1974 {
James Feistacc8a4e2019-04-02 14:23:57 -07001975 phosphor::logging::log<phosphor::logging::level::ERR>(
1976 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1977 "configurations");
1978 return ipmi::responseResponseError();
1979 }
1980 std::string type = std::get<std::string>(findClass->second);
1981 if (type == "fan")
1982 {
1983 auto findOutLimit = pid.find("OutLimitMin");
1984 if (findOutLimit == pid.end())
1985 {
James Feistacc8a4e2019-04-02 14:23:57 -07001986 phosphor::logging::log<phosphor::logging::level::ERR>(
1987 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1988 "configurations");
1989 return ipmi::responseResponseError();
1990 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001991 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001992 path, pidConfigurationIface, "OutLimitMin",
1993 static_cast<double>(offset));
1994 found = true;
1995 }
1996 }
1997 if (!found)
1998 {
1999 phosphor::logging::log<phosphor::logging::level::ERR>(
2000 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
2001 return ipmi::responseResponseError();
2002 }
2003
2004 return ipmi::responseSuccess();
2005}
2006
2007ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
2008 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07002009{
2010 constexpr const size_t disableLimiting = 0x0;
2011
Vernon Mauery15419dd2019-05-24 09:40:30 -07002012 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002013 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002014 {
James Feist09f6b602019-08-08 11:30:03 -07002015 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07002016 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07002017 {
James Feist09f6b602019-08-08 11:30:03 -07002018 pathName = exitAirPathName;
2019 }
2020 else if (param1 == legacyPCHSensorNumber)
2021 {
2022 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07002023 }
2024 else
2025 {
James Feistacc8a4e2019-04-02 14:23:57 -07002026 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002027 }
James Feist09f6b602019-08-08 11:30:03 -07002028 std::string path = getConfigPath(pathName);
2029 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
2030 pidConfigurationIface, "SetPoint",
2031 static_cast<double>(param2));
2032 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07002033 }
James Feistacc8a4e2019-04-02 14:23:57 -07002034 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002035 {
James Feistacc8a4e2019-04-02 14:23:57 -07002036 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07002037
2038 // must be greater than 50 based on eps
2039 if (cfm < 50 && cfm != disableLimiting)
2040 {
James Feistacc8a4e2019-04-02 14:23:57 -07002041 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002042 }
2043
2044 try
2045 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002046 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07002047 cfmLimitIface, "Limit",
2048 static_cast<double>(cfm));
2049 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002050 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002051 {
2052 phosphor::logging::log<phosphor::logging::level::ERR>(
2053 "ipmiOEMSetFscParameter: can't set cfm setting!",
2054 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002055 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002056 }
James Feistacc8a4e2019-04-02 14:23:57 -07002057 return ipmi::responseSuccess();
2058 }
2059 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2060 {
2061 constexpr const size_t maxDomainCount = 8;
2062 uint8_t requestedDomainMask = param1;
2063 boost::container::flat_map data = getPidConfigs();
2064 if (data.empty())
2065 {
James Feistacc8a4e2019-04-02 14:23:57 -07002066 phosphor::logging::log<phosphor::logging::level::ERR>(
2067 "ipmiOEMSetFscParameter: found no pid configurations!");
2068 return ipmi::responseResponseError();
2069 }
2070 size_t count = 0;
2071 for (const auto& [path, pid] : data)
2072 {
2073 auto findClass = pid.find("Class");
2074 if (findClass == pid.end())
2075 {
James Feistacc8a4e2019-04-02 14:23:57 -07002076 phosphor::logging::log<phosphor::logging::level::ERR>(
2077 "ipmiOEMSetFscParameter: found illegal pid "
2078 "configurations");
2079 return ipmi::responseResponseError();
2080 }
2081 std::string type = std::get<std::string>(findClass->second);
2082 if (type == "fan")
2083 {
2084 if (requestedDomainMask & (1 << count))
2085 {
2086 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002087 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07002088 pidConfigurationIface, "OutLimitMax",
2089 static_cast<double>(param2));
2090 }
2091 count++;
2092 }
2093 }
2094 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07002095 }
2096 else
2097 {
2098 // todo other command parts possibly
2099 // tcontrol is handled in peci now
2100 // fan speed offset not implemented yet
2101 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002102 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002103 }
2104}
2105
James Feistacc8a4e2019-04-02 14:23:57 -07002106ipmi::RspType<
2107 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2108 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002109{
James Feist09f6b602019-08-08 11:30:03 -07002110 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002111
Vernon Mauery15419dd2019-05-24 09:40:30 -07002112 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002113 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002114 {
James Feistacc8a4e2019-04-02 14:23:57 -07002115 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002116 {
James Feistacc8a4e2019-04-02 14:23:57 -07002117 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002118 }
2119
James Feist09f6b602019-08-08 11:30:03 -07002120 std::string pathName;
2121
2122 if (*param == legacyExitAirSensorNumber)
2123 {
2124 pathName = exitAirPathName;
2125 }
2126 else if (*param == legacyPCHSensorNumber)
2127 {
2128 pathName = pchPathName;
2129 }
2130 else
James Feistfaa4f222019-03-21 16:21:55 -07002131 {
James Feistacc8a4e2019-04-02 14:23:57 -07002132 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002133 }
James Feist09f6b602019-08-08 11:30:03 -07002134
2135 uint8_t setpoint = legacyDefaultSetpoint;
2136 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002137 if (path.size())
2138 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002139 Value val = ipmi::getDbusProperty(
2140 *dbus, "xyz.openbmc_project.EntityManager", path,
2141 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002142 setpoint = std::floor(std::get<double>(val) + 0.5);
2143 }
2144
2145 // old implementation used to return the "default" and current, we
2146 // don't make the default readily available so just make both the
2147 // same
James Feistfaa4f222019-03-21 16:21:55 -07002148
James Feistacc8a4e2019-04-02 14:23:57 -07002149 return ipmi::responseSuccess(
2150 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002151 }
James Feistacc8a4e2019-04-02 14:23:57 -07002152 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2153 {
2154 constexpr const size_t maxDomainCount = 8;
2155
2156 if (!param)
2157 {
2158 return ipmi::responseReqDataLenInvalid();
2159 }
2160 uint8_t requestedDomain = *param;
2161 if (requestedDomain >= maxDomainCount)
2162 {
2163 return ipmi::responseInvalidFieldRequest();
2164 }
2165
2166 boost::container::flat_map data = getPidConfigs();
2167 if (data.empty())
2168 {
2169 phosphor::logging::log<phosphor::logging::level::ERR>(
2170 "ipmiOEMGetFscParameter: found no pid configurations!");
2171 return ipmi::responseResponseError();
2172 }
2173 size_t count = 0;
2174 for (const auto& [_, pid] : data)
2175 {
2176 auto findClass = pid.find("Class");
2177 if (findClass == pid.end())
2178 {
2179 phosphor::logging::log<phosphor::logging::level::ERR>(
2180 "ipmiOEMGetFscParameter: found illegal pid "
2181 "configurations");
2182 return ipmi::responseResponseError();
2183 }
2184 std::string type = std::get<std::string>(findClass->second);
2185 if (type == "fan")
2186 {
2187 if (requestedDomain == count)
2188 {
2189 auto findOutLimit = pid.find("OutLimitMax");
2190 if (findOutLimit == pid.end())
2191 {
2192 phosphor::logging::log<phosphor::logging::level::ERR>(
2193 "ipmiOEMGetFscParameter: found illegal pid "
2194 "configurations");
2195 return ipmi::responseResponseError();
2196 }
2197
2198 return ipmi::responseSuccess(
2199 static_cast<uint8_t>(std::floor(
2200 std::get<double>(findOutLimit->second) + 0.5)));
2201 }
2202 else
2203 {
2204 count++;
2205 }
2206 }
2207 }
2208
2209 return ipmi::responseInvalidFieldRequest();
2210 }
2211 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002212 {
James Feist5f957ca2019-03-14 15:33:55 -07002213 /*
2214 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002215 previous behavior didn't seem to prevent this, ignore the check for
2216 now.
James Feist5f957ca2019-03-14 15:33:55 -07002217
James Feistacc8a4e2019-04-02 14:23:57 -07002218 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002219 {
2220 phosphor::logging::log<phosphor::logging::level::ERR>(
2221 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002222 return IPMI_CC_REQ_DATA_LEN_INVALID;
2223 }
2224 */
2225 Value cfmLimit;
2226 Value cfmMaximum;
2227 try
2228 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002229 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002230 cfmLimitSettingPath, cfmLimitIface,
2231 "Limit");
2232 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002233 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002234 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2235 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002236 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002237 {
2238 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002239 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002240 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002241 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002242 }
2243
James Feistacc8a4e2019-04-02 14:23:57 -07002244 double cfmMax = std::get<double>(cfmMaximum);
2245 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002246
James Feistacc8a4e2019-04-02 14:23:57 -07002247 cfmLim = std::floor(cfmLim + 0.5);
2248 cfmMax = std::floor(cfmMax + 0.5);
2249 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2250 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002251
James Feistacc8a4e2019-04-02 14:23:57 -07002252 return ipmi::responseSuccess(
2253 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002254 }
James Feistacc8a4e2019-04-02 14:23:57 -07002255
James Feist5f957ca2019-03-14 15:33:55 -07002256 else
2257 {
2258 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002259 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002260 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002261 }
2262}
2263
Jason M. Bills0748c692022-09-08 15:34:08 -07002264using crConfigVariant = ipmi::DbusVariant;
Cheng C Yang773703a2019-08-15 09:41:11 +08002265
2266int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2267 const crConfigVariant& value,
2268 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2269{
2270 boost::system::error_code ec;
2271 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002272 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002273 "/xyz/openbmc_project/control/power_supply_redundancy",
2274 "org.freedesktop.DBus.Properties", "Set",
2275 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2276 if (ec)
2277 {
2278 phosphor::logging::log<phosphor::logging::level::ERR>(
2279 "Failed to set dbus property to cold redundancy");
2280 return -1;
2281 }
2282
2283 return 0;
2284}
2285
Kuiying Wange45333a2020-07-22 22:06:37 +08002286int getCRConfig(
2287 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2288 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2289 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002290{
2291 boost::system::error_code ec;
2292 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002293 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002294 "/xyz/openbmc_project/control/power_supply_redundancy",
2295 "org.freedesktop.DBus.Properties", "Get",
2296 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2297 if (ec)
2298 {
2299 phosphor::logging::log<phosphor::logging::level::ERR>(
2300 "Failed to get dbus property to cold redundancy");
2301 return -1;
2302 }
2303 return 0;
2304}
2305
2306uint8_t getPSUCount(void)
2307{
2308 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2309 ipmi::Value num;
2310 try
2311 {
2312 num = ipmi::getDbusProperty(
2313 *dbus, "xyz.openbmc_project.PSURedundancy",
2314 "/xyz/openbmc_project/control/power_supply_redundancy",
2315 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2316 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002317 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002318 {
2319 phosphor::logging::log<phosphor::logging::level::ERR>(
2320 "Failed to get PSUNumber property from dbus interface");
2321 return 0;
2322 }
2323 uint8_t* pNum = std::get_if<uint8_t>(&num);
2324 if (!pNum)
2325 {
2326 phosphor::logging::log<phosphor::logging::level::ERR>(
2327 "Error to get PSU Number");
2328 return 0;
2329 }
2330 return *pNum;
2331}
2332
2333bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2334{
2335 if (conf.size() < num)
2336 {
2337 phosphor::logging::log<phosphor::logging::level::ERR>(
2338 "Invalid PSU Ranking");
2339 return false;
2340 }
2341 std::set<uint8_t> confSet;
2342 for (uint8_t i = 0; i < num; i++)
2343 {
2344 if (conf[i] > num)
2345 {
2346 phosphor::logging::log<phosphor::logging::level::ERR>(
2347 "PSU Ranking is larger than current PSU number");
2348 return false;
2349 }
2350 confSet.emplace(conf[i]);
2351 }
2352
2353 if (confSet.size() != num)
2354 {
2355 phosphor::logging::log<phosphor::logging::level::ERR>(
2356 "duplicate PSU Ranking");
2357 return false;
2358 }
2359 return true;
2360}
2361
2362enum class crParameter
2363{
2364 crStatus = 0,
2365 crFeature = 1,
2366 rotationFeature = 2,
2367 rotationAlgo = 3,
2368 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002369 numOfPSU = 5,
2370 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002371};
2372
2373constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2374static const constexpr uint32_t oneDay = 0x15180;
2375static const constexpr uint32_t oneMonth = 0xf53700;
2376static const constexpr uint8_t userSpecific = 0x01;
2377static const constexpr uint8_t crSetCompleted = 0;
2378ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2379 uint8_t parameter,
2380 ipmi::message::Payload& payload)
2381{
2382 switch (static_cast<crParameter>(parameter))
2383 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002384 case crParameter::rotationFeature:
2385 {
2386 uint8_t param1;
2387 if (payload.unpack(param1) || !payload.fullyUnpacked())
2388 {
2389 return ipmi::responseReqDataLenInvalid();
2390 }
2391 // Rotation Enable can only be true or false
2392 if (param1 > 1)
2393 {
2394 return ipmi::responseInvalidFieldRequest();
2395 }
2396 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2397 {
2398 return ipmi::responseResponseError();
2399 }
2400 break;
2401 }
2402 case crParameter::rotationAlgo:
2403 {
2404 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2405 std::string algoName;
2406 uint8_t param1;
2407 if (payload.unpack(param1))
2408 {
2409 return ipmi::responseReqDataLenInvalid();
2410 }
2411 switch (param1)
2412 {
2413 case 0:
2414 algoName = "xyz.openbmc_project.Control."
2415 "PowerSupplyRedundancy.Algo.bmcSpecific";
2416 break;
2417 case 1:
2418 algoName = "xyz.openbmc_project.Control."
2419 "PowerSupplyRedundancy.Algo.userSpecific";
2420 break;
2421 default:
2422 return ipmi::responseInvalidFieldRequest();
2423 }
2424 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2425 {
2426 return ipmi::responseResponseError();
2427 }
2428
2429 uint8_t numberOfPSU = getPSUCount();
2430 if (!numberOfPSU)
2431 {
2432 return ipmi::responseResponseError();
2433 }
2434 std::vector<uint8_t> rankOrder;
2435
2436 if (param1 == userSpecific)
2437 {
2438 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2439 {
2440 ipmi::responseReqDataLenInvalid();
2441 }
Yong Li83315132019-10-23 17:42:24 +08002442 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002443 {
2444 return ipmi::responseReqDataLenInvalid();
2445 }
2446
2447 if (!validateCRAlgo(rankOrder, numberOfPSU))
2448 {
2449 return ipmi::responseInvalidFieldRequest();
2450 }
2451 }
2452 else
2453 {
2454 if (rankOrder.size() > 0)
2455 {
2456 return ipmi::responseReqDataLenInvalid();
2457 }
2458 for (uint8_t i = 1; i <= numberOfPSU; i++)
2459 {
2460 rankOrder.emplace_back(i);
2461 }
2462 }
2463 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2464 {
2465 return ipmi::responseResponseError();
2466 }
2467 break;
2468 }
2469 case crParameter::rotationPeriod:
2470 {
2471 // Minimum Rotation period is One day (86400 seconds) and Max
2472 // Rotation Period is 6 month (0xf53700 seconds)
2473 uint32_t period;
2474 if (payload.unpack(period) || !payload.fullyUnpacked())
2475 {
2476 return ipmi::responseReqDataLenInvalid();
2477 }
2478 if ((period < oneDay) || (period > oneMonth))
2479 {
2480 return ipmi::responseInvalidFieldRequest();
2481 }
2482 if (setCRConfig(ctx, "PeriodOfRotation", period))
2483 {
2484 return ipmi::responseResponseError();
2485 }
2486 break;
2487 }
2488 default:
2489 {
2490 return ipmi::response(ccParameterNotSupported);
2491 }
2492 }
2493
Cheng C Yang773703a2019-08-15 09:41:11 +08002494 return ipmi::responseSuccess(crSetCompleted);
2495}
2496
Yong Li83315132019-10-23 17:42:24 +08002497ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002498 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2499{
2500 crConfigVariant value;
2501 switch (static_cast<crParameter>(parameter))
2502 {
2503 case crParameter::crStatus:
2504 {
2505 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2506 {
2507 return ipmi::responseResponseError();
2508 }
2509 std::string* pStatus = std::get_if<std::string>(&value);
2510 if (!pStatus)
2511 {
2512 phosphor::logging::log<phosphor::logging::level::ERR>(
2513 "Error to get ColdRedundancyStatus property");
2514 return ipmi::responseResponseError();
2515 }
2516 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2517 auto status =
2518 server::PowerSupplyRedundancy::convertStatusFromString(
2519 *pStatus);
2520 switch (status)
2521 {
2522 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002523 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002524 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002525
2526 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002527 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002528 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002529 default:
2530 phosphor::logging::log<phosphor::logging::level::ERR>(
2531 "Error to get valid status");
2532 return ipmi::responseResponseError();
2533 }
2534 }
2535 case crParameter::crFeature:
2536 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002537 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002538 {
2539 return ipmi::responseResponseError();
2540 }
2541 bool* pResponse = std::get_if<bool>(&value);
2542 if (!pResponse)
2543 {
2544 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002545 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002546 return ipmi::responseResponseError();
2547 }
2548
Cheng C Yangf41e3342019-09-10 04:47:23 +08002549 return ipmi::responseSuccess(parameter,
2550 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002551 }
2552 case crParameter::rotationFeature:
2553 {
2554 if (getCRConfig(ctx, "RotationEnabled", value))
2555 {
2556 return ipmi::responseResponseError();
2557 }
2558 bool* pResponse = std::get_if<bool>(&value);
2559 if (!pResponse)
2560 {
2561 phosphor::logging::log<phosphor::logging::level::ERR>(
2562 "Error to get RotationEnabled property");
2563 return ipmi::responseResponseError();
2564 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002565 return ipmi::responseSuccess(parameter,
2566 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002567 }
2568 case crParameter::rotationAlgo:
2569 {
2570 if (getCRConfig(ctx, "RotationAlgorithm", value))
2571 {
2572 return ipmi::responseResponseError();
2573 }
2574
2575 std::string* pAlgo = std::get_if<std::string>(&value);
2576 if (!pAlgo)
2577 {
2578 phosphor::logging::log<phosphor::logging::level::ERR>(
2579 "Error to get RotationAlgorithm property");
2580 return ipmi::responseResponseError();
2581 }
Yong Li83315132019-10-23 17:42:24 +08002582 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002583 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2584 auto algo =
2585 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002586
Cheng C Yang773703a2019-08-15 09:41:11 +08002587 switch (algo)
2588 {
2589 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002590 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002591 break;
2592 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002593 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002594 break;
2595 default:
2596 phosphor::logging::log<phosphor::logging::level::ERR>(
2597 "Error to get valid algo");
2598 return ipmi::responseResponseError();
2599 }
2600
2601 if (getCRConfig(ctx, "RotationRankOrder", value))
2602 {
2603 return ipmi::responseResponseError();
2604 }
2605 std::vector<uint8_t>* pResponse =
2606 std::get_if<std::vector<uint8_t>>(&value);
2607 if (!pResponse)
2608 {
2609 phosphor::logging::log<phosphor::logging::level::ERR>(
2610 "Error to get RotationRankOrder property");
2611 return ipmi::responseResponseError();
2612 }
Yong Li83315132019-10-23 17:42:24 +08002613
Cheng C Yang773703a2019-08-15 09:41:11 +08002614 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002615 std::back_inserter(response));
2616
Cheng C Yangf41e3342019-09-10 04:47:23 +08002617 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002618 }
2619 case crParameter::rotationPeriod:
2620 {
2621 if (getCRConfig(ctx, "PeriodOfRotation", value))
2622 {
2623 return ipmi::responseResponseError();
2624 }
2625 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2626 if (!pResponse)
2627 {
2628 phosphor::logging::log<phosphor::logging::level::ERR>(
2629 "Error to get RotationAlgorithm property");
2630 return ipmi::responseResponseError();
2631 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002632 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002633 }
2634 case crParameter::numOfPSU:
2635 {
2636 uint8_t numberOfPSU = getPSUCount();
2637 if (!numberOfPSU)
2638 {
2639 return ipmi::responseResponseError();
2640 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002641 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002642 }
Yong Li19445ab2019-12-20 18:25:29 +08002643 case crParameter::rotationRankOrderEffective:
2644 {
2645 if (getCRConfig(ctx, "RotationRankOrder", value,
2646 "xyz.openbmc_project.PSURedundancy"))
2647 {
2648 return ipmi::responseResponseError();
2649 }
2650 std::vector<uint8_t>* pResponse =
2651 std::get_if<std::vector<uint8_t>>(&value);
2652 if (!pResponse)
2653 {
2654 phosphor::logging::log<phosphor::logging::level::ERR>(
2655 "Error to get effective RotationRankOrder property");
2656 return ipmi::responseResponseError();
2657 }
2658 return ipmi::responseSuccess(parameter, *pResponse);
2659 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002660 default:
2661 {
2662 return ipmi::response(ccParameterNotSupported);
2663 }
2664 }
2665}
2666
Zhu, Yungebe560b02019-04-21 21:19:21 -04002667ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2668 uint8_t faultState,
2669 uint8_t faultGroup,
2670 std::array<uint8_t, 8>& ledStateData)
2671{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002672 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2673 static const std::array<std::string, maxFaultType> faultNames = {
2674 "faultFan", "faultTemp", "faultPower",
2675 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002676
2677 constexpr uint8_t maxFaultSource = 0x4;
2678 constexpr uint8_t skipLEDs = 0xFF;
2679 constexpr uint8_t pinSize = 64;
2680 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002681 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002682
Zhikui Rence4e73f2019-12-06 13:59:47 -08002683 // same pin names need to be defined in dts file
2684 static const std::array<std::array<std::string, groupSize>, groupNum>
2685 faultLedPinNames = {{
2686 "LED_CPU1_CH1_DIMM1_FAULT",
2687 "LED_CPU1_CH1_DIMM2_FAULT",
2688 "LED_CPU1_CH2_DIMM1_FAULT",
2689 "LED_CPU1_CH2_DIMM2_FAULT",
2690 "LED_CPU1_CH3_DIMM1_FAULT",
2691 "LED_CPU1_CH3_DIMM2_FAULT",
2692 "LED_CPU1_CH4_DIMM1_FAULT",
2693 "LED_CPU1_CH4_DIMM2_FAULT",
2694 "LED_CPU1_CH5_DIMM1_FAULT",
2695 "LED_CPU1_CH5_DIMM2_FAULT",
2696 "LED_CPU1_CH6_DIMM1_FAULT",
2697 "LED_CPU1_CH6_DIMM2_FAULT",
2698 "",
2699 "",
2700 "",
2701 "", // end of group1
2702 "LED_CPU2_CH1_DIMM1_FAULT",
2703 "LED_CPU2_CH1_DIMM2_FAULT",
2704 "LED_CPU2_CH2_DIMM1_FAULT",
2705 "LED_CPU2_CH2_DIMM2_FAULT",
2706 "LED_CPU2_CH3_DIMM1_FAULT",
2707 "LED_CPU2_CH3_DIMM2_FAULT",
2708 "LED_CPU2_CH4_DIMM1_FAULT",
2709 "LED_CPU2_CH4_DIMM2_FAULT",
2710 "LED_CPU2_CH5_DIMM1_FAULT",
2711 "LED_CPU2_CH5_DIMM2_FAULT",
2712 "LED_CPU2_CH6_DIMM1_FAULT",
2713 "LED_CPU2_CH6_DIMM2_FAULT",
2714 "",
2715 "",
2716 "",
2717 "", // endof group2
2718 "LED_CPU3_CH1_DIMM1_FAULT",
2719 "LED_CPU3_CH1_DIMM2_FAULT",
2720 "LED_CPU3_CH2_DIMM1_FAULT",
2721 "LED_CPU3_CH2_DIMM2_FAULT",
2722 "LED_CPU3_CH3_DIMM1_FAULT",
2723 "LED_CPU3_CH3_DIMM2_FAULT",
2724 "LED_CPU3_CH4_DIMM1_FAULT",
2725 "LED_CPU3_CH4_DIMM2_FAULT",
2726 "LED_CPU3_CH5_DIMM1_FAULT",
2727 "LED_CPU3_CH5_DIMM2_FAULT",
2728 "LED_CPU3_CH6_DIMM1_FAULT",
2729 "LED_CPU3_CH6_DIMM2_FAULT",
2730 "",
2731 "",
2732 "",
2733 "", // end of group3
2734 "LED_CPU4_CH1_DIMM1_FAULT",
2735 "LED_CPU4_CH1_DIMM2_FAULT",
2736 "LED_CPU4_CH2_DIMM1_FAULT",
2737 "LED_CPU4_CH2_DIMM2_FAULT",
2738 "LED_CPU4_CH3_DIMM1_FAULT",
2739 "LED_CPU4_CH3_DIMM2_FAULT",
2740 "LED_CPU4_CH4_DIMM1_FAULT",
2741 "LED_CPU4_CH4_DIMM2_FAULT",
2742 "LED_CPU4_CH5_DIMM1_FAULT",
2743 "LED_CPU4_CH5_DIMM2_FAULT",
2744 "LED_CPU4_CH6_DIMM1_FAULT",
2745 "LED_CPU4_CH6_DIMM2_FAULT",
2746 "",
2747 "",
2748 "",
2749 "", // end of group4
2750 "LED_FAN1_FAULT",
2751 "LED_FAN2_FAULT",
2752 "LED_FAN3_FAULT",
2753 "LED_FAN4_FAULT",
2754 "LED_FAN5_FAULT",
2755 "LED_FAN6_FAULT",
2756 "LED_FAN7_FAULT",
2757 "LED_FAN8_FAULT",
2758 "",
2759 "",
2760 "",
2761 "",
2762 "",
2763 "",
2764 "",
2765 "" // end of group5
2766 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002767
Zhikui Rence4e73f2019-12-06 13:59:47 -08002768 // Validate the source, fault type --
2769 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2770 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2771 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2772 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2773 // definition differs based on fault type (Byte 2)
2774 // Type Fan=> Group: 0=FanGroupID, FF-not used
2775 // Byte 5-11 00h, not used
2776 // Byte12 FanLedState [7:0]-Fans 7:0
2777 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2778 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2779 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2780 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2781 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2782 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2783 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2784 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002785 if ((sourceId >= maxFaultSource) ||
2786 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2787 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2788 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2789 {
2790 return ipmi::responseParmOutOfRange();
2791 }
2792
Zhikui Rence4e73f2019-12-06 13:59:47 -08002793 size_t pinGroupOffset = 0;
2794 size_t pinGroupMax = pinSize / groupSize;
2795 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002796 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002797 pinGroupOffset = 4;
2798 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002799 }
2800
2801 switch (RemoteFaultType(faultType))
2802 {
2803 case (RemoteFaultType::fan):
2804 case (RemoteFaultType::memory):
2805 {
2806 if (faultGroup == skipLEDs)
2807 {
2808 return ipmi::responseSuccess();
2809 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002810 // calculate led state bit filed count, each byte has 8bits
2811 // the maximum bits will be 8 * 8 bits
2812 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002813
2814 // assemble ledState
2815 uint64_t ledState = 0;
2816 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002817 for (int i = 0; i < sizeof(ledStateData); i++)
2818 {
2819 ledState = (uint64_t)(ledState << 8);
2820 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2821 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002822 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002823
Zhikui Rence4e73f2019-12-06 13:59:47 -08002824 for (int group = 0; group < pinGroupMax; group++)
2825 {
2826 for (int i = 0; i < groupSize; i++)
2827 { // skip non-existing pins
2828 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2829 {
2830 continue;
2831 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002832
Zhikui Rence4e73f2019-12-06 13:59:47 -08002833 gpiod::line line = gpiod::find_line(
2834 faultLedPinNames[group + pinGroupOffset][i]);
2835 if (!line)
2836 {
2837 phosphor::logging::log<phosphor::logging::level::ERR>(
2838 "Not Find Led Gpio Device!",
2839 phosphor::logging::entry(
2840 "DEVICE=%s",
2841 faultLedPinNames[group + pinGroupOffset][i]
2842 .c_str()));
2843 hasError = true;
2844 continue;
2845 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002846
Zhikui Rence4e73f2019-12-06 13:59:47 -08002847 bool activeHigh =
2848 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2849 try
2850 {
2851 line.request(
2852 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2853 activeHigh
2854 ? 0
2855 : gpiod::line_request::FLAG_ACTIVE_LOW});
2856 line.set_value(ledStateBits[i + group * groupSize]);
2857 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002858 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002859 {
2860 phosphor::logging::log<phosphor::logging::level::ERR>(
2861 "Error write Led Gpio Device!",
2862 phosphor::logging::entry(
2863 "DEVICE=%s",
2864 faultLedPinNames[group + pinGroupOffset][i]
2865 .c_str()));
2866 hasError = true;
2867 continue;
2868 }
2869 } // for int i
2870 }
2871 if (hasError)
2872 {
2873 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002874 }
2875 break;
2876 }
2877 default:
2878 {
2879 // now only support two fault types
2880 return ipmi::responseParmOutOfRange();
2881 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002882 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002883 return ipmi::responseSuccess();
2884}
2885
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302886ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2887{
2888 uint8_t prodId = 0;
2889 try
2890 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002891 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302892 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002893 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302894 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2895 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002896 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302897 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2898 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302899 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2900 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002901 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302902 {
2903 phosphor::logging::log<phosphor::logging::level::ERR>(
2904 "ipmiOEMReadBoardProductId: Product ID read failed!",
2905 phosphor::logging::entry("ERR=%s", e.what()));
2906 }
2907 return ipmi::responseSuccess(prodId);
2908}
2909
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302910/** @brief implements the get security mode command
2911 * @param ctx - ctx pointer
2912 *
2913 * @returns IPMI completion code with following data
2914 * - restriction mode value - As specified in
2915 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2916 * - special mode value - As specified in
2917 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2918 */
2919ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2920{
2921 namespace securityNameSpace =
2922 sdbusplus::xyz::openbmc_project::Control::Security::server;
2923 uint8_t restrictionModeValue = 0;
2924 uint8_t specialModeValue = 0;
2925
2926 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07002927 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07002928 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302929 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2930 restricionModeProperty);
2931 if (ec)
2932 {
2933 phosphor::logging::log<phosphor::logging::level::ERR>(
2934 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2935 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2936 return ipmi::responseUnspecifiedError();
2937 }
2938 restrictionModeValue = static_cast<uint8_t>(
2939 securityNameSpace::RestrictionMode::convertModesFromString(
2940 std::get<std::string>(varRestrMode)));
Jason M. Bills0748c692022-09-08 15:34:08 -07002941 auto varSpecialMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
2942 ctx->yield, ec, specialModeService, specialModeBasePath,
2943 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2944 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302945 if (ec)
2946 {
2947 phosphor::logging::log<phosphor::logging::level::ERR>(
2948 "ipmiGetSecurityMode: failed to get SpecialMode property",
2949 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2950 // fall through, let us not worry about SpecialMode property, which is
2951 // not required in user scenario
2952 }
2953 else
2954 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302955 specialModeValue = static_cast<uint8_t>(
2956 securityNameSpace::SpecialMode::convertModesFromString(
2957 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302958 }
2959 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2960}
2961
2962/** @brief implements the set security mode command
2963 * Command allows to upgrade the restriction mode and won't allow
2964 * to downgrade from system interface
2965 * @param ctx - ctx pointer
2966 * @param restrictionMode - restriction mode value to be set.
2967 *
2968 * @returns IPMI completion code
2969 */
2970ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302971 uint8_t restrictionMode,
2972 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302973{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302974#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2975 if (specialMode)
2976 {
2977 return ipmi::responseReqDataLenInvalid();
2978 }
2979#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302980 namespace securityNameSpace =
2981 sdbusplus::xyz::openbmc_project::Control::Security::server;
2982
2983 ChannelInfo chInfo;
2984 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2985 {
2986 phosphor::logging::log<phosphor::logging::level::ERR>(
2987 "ipmiSetSecurityMode: Failed to get Channel Info",
2988 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2989 return ipmi::responseUnspecifiedError();
2990 }
2991 auto reqMode =
2992 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2993
2994 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2995 (reqMode >
2996 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2997 {
2998 return ipmi::responseInvalidFieldRequest();
2999 }
3000
3001 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07003002 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07003003 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303004 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
3005 restricionModeProperty);
3006 if (ec)
3007 {
3008 phosphor::logging::log<phosphor::logging::level::ERR>(
3009 "ipmiSetSecurityMode: failed to get RestrictionMode property",
3010 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3011 return ipmi::responseUnspecifiedError();
3012 }
3013 auto currentRestrictionMode =
3014 securityNameSpace::RestrictionMode::convertModesFromString(
3015 std::get<std::string>(varRestrMode));
3016
3017 if (chInfo.mediumType !=
3018 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
3019 currentRestrictionMode > reqMode)
3020 {
3021 phosphor::logging::log<phosphor::logging::level::ERR>(
3022 "ipmiSetSecurityMode - Downgrading security mode not supported "
3023 "through system interface",
3024 phosphor::logging::entry(
3025 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
3026 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
3027 return ipmi::responseCommandNotAvailable();
3028 }
3029
3030 ec.clear();
3031 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07003032 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303033 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
3034 restricionModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003035 static_cast<ipmi::DbusVariant>(
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303036 securityNameSpace::convertForMessage(reqMode)));
3037
3038 if (ec)
3039 {
3040 phosphor::logging::log<phosphor::logging::level::ERR>(
3041 "ipmiSetSecurityMode: failed to set RestrictionMode property",
3042 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3043 return ipmi::responseUnspecifiedError();
3044 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303045
3046#ifdef BMC_VALIDATION_UNSECURE_FEATURE
3047 if (specialMode)
3048 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00003049 constexpr uint8_t mfgMode = 0x01;
3050 // Manufacturing mode is reserved. So can't enable this mode.
3051 if (specialMode.value() == mfgMode)
3052 {
3053 phosphor::logging::log<phosphor::logging::level::INFO>(
3054 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
3055 return ipmi::responseInvalidFieldRequest();
3056 }
3057
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303058 ec.clear();
3059 ctx->bus->yield_method_call<>(
3060 ctx->yield, ec, specialModeService, specialModeBasePath,
3061 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
3062 specialModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003063 static_cast<ipmi::DbusVariant>(securityNameSpace::convertForMessage(
3064 static_cast<securityNameSpace::SpecialMode::Modes>(
3065 specialMode.value()))));
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303066
3067 if (ec)
3068 {
3069 phosphor::logging::log<phosphor::logging::level::ERR>(
3070 "ipmiSetSecurityMode: failed to set SpecialMode property",
3071 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3072 return ipmi::responseUnspecifiedError();
3073 }
3074 }
3075#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303076 return ipmi::responseSuccess();
3077}
3078
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003079ipmi::RspType<uint8_t /* restore status */>
3080 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
3081{
3082 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
3083
3084 if (clr != expClr)
3085 {
3086 return ipmi::responseInvalidFieldRequest();
3087 }
3088 constexpr uint8_t cmdStatus = 0;
3089 constexpr uint8_t cmdDefaultRestore = 0xaa;
3090 constexpr uint8_t cmdFullRestore = 0xbb;
3091 constexpr uint8_t cmdFormat = 0xcc;
3092
3093 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3094
3095 switch (cmd)
3096 {
3097 case cmdStatus:
3098 break;
3099 case cmdDefaultRestore:
3100 case cmdFullRestore:
3101 case cmdFormat:
3102 {
3103 // write file to rwfs root
3104 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3105 std::ofstream restoreFile(restoreOpFname);
3106 if (!restoreFile)
3107 {
3108 return ipmi::responseUnspecifiedError();
3109 }
3110 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303111
3112 phosphor::logging::log<phosphor::logging::level::WARNING>(
3113 "Restore to default will be performed on next BMC boot",
3114 phosphor::logging::entry("ACTION=0x%0X", cmd));
3115
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003116 break;
3117 }
3118 default:
3119 return ipmi::responseInvalidFieldRequest();
3120 }
3121
3122 constexpr uint8_t restorePending = 0;
3123 constexpr uint8_t restoreComplete = 1;
3124
3125 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3126 ? restorePending
3127 : restoreComplete;
3128 return ipmi::responseSuccess(restoreStatus);
3129}
3130
Chen Yugang39736d52019-07-12 16:24:33 +08003131ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3132{
3133 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003134 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003135
3136 try
3137 {
3138 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05003139 std::string service = getService(*dbus, oemNmiSourceIntf,
3140 oemNmiSourceObjPath);
3141 Value variant = getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3142 oemNmiSourceIntf,
3143 oemNmiBmcSourceObjPathProp);
Chen Yugang39736d52019-07-12 16:24:33 +08003144
3145 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3146 std::get<std::string>(variant)))
3147 {
3148 case nmi::NMISource::BMCSourceSignal::None:
3149 bmcSource = static_cast<uint8_t>(NmiSource::none);
3150 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003151 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3152 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003153 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003154 case nmi::NMISource::BMCSourceSignal::Watchdog:
3155 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003156 break;
3157 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3158 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3159 break;
3160 case nmi::NMISource::BMCSourceSignal::MemoryError:
3161 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3162 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003163 case nmi::NMISource::BMCSourceSignal::PciBusError:
3164 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003165 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003166 case nmi::NMISource::BMCSourceSignal::PCH:
3167 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003168 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003169 case nmi::NMISource::BMCSourceSignal::Chipset:
3170 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003171 break;
3172 default:
3173 phosphor::logging::log<phosphor::logging::level::ERR>(
3174 "NMI source: invalid property!",
3175 phosphor::logging::entry(
3176 "PROP=%s", std::get<std::string>(variant).c_str()));
3177 return ipmi::responseResponseError();
3178 }
3179 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05003180 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003181 {
3182 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3183 return ipmi::responseResponseError();
3184 }
3185
3186 return ipmi::responseSuccess(bmcSource);
3187}
3188
3189ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3190{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003191 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003192
3193 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3194 nmi::NMISource::BMCSourceSignal::None;
3195
3196 switch (NmiSource(sourceId))
3197 {
3198 case NmiSource::none:
3199 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3200 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003201 case NmiSource::frontPanelButton:
3202 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003203 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003204 case NmiSource::watchdog:
3205 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003206 break;
3207 case NmiSource::chassisCmd:
3208 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3209 break;
3210 case NmiSource::memoryError:
3211 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3212 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003213 case NmiSource::pciBusError:
3214 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003215 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003216 case NmiSource::pch:
3217 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003218 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003219 case NmiSource::chipset:
3220 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003221 break;
3222 default:
3223 phosphor::logging::log<phosphor::logging::level::ERR>(
3224 "NMI source: invalid property!");
3225 return ipmi::responseResponseError();
3226 }
3227
3228 try
3229 {
3230 // keep NMI signal source
3231 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Patrick Williamsb37abfb2023-05-10 07:50:33 -05003232 std::string service = getService(*dbus, oemNmiSourceIntf,
3233 oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003234 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3235 oemNmiBmcSourceObjPathProp,
3236 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003237 // set Enabled property to inform NMI source handling
3238 // to trigger a NMI_OUT BSOD.
3239 // if it's triggered by NMI source property changed,
3240 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3241 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3242 {
3243 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3244 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3245 static_cast<bool>(true));
3246 }
Chen Yugang39736d52019-07-12 16:24:33 +08003247 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003248 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003249 {
3250 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3251 return ipmi::responseResponseError();
3252 }
3253
3254 return ipmi::responseSuccess();
3255}
3256
James Feist63efafa2019-07-24 12:39:21 -07003257namespace dimmOffset
3258{
3259constexpr const char* dimmPower = "DimmPower";
3260constexpr const char* staticCltt = "StaticCltt";
3261constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3262constexpr const char* offsetInterface =
3263 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3264constexpr const char* property = "DimmOffset";
3265
3266}; // namespace dimmOffset
3267
3268ipmi::RspType<>
3269 ipmiOEMSetDimmOffset(uint8_t type,
3270 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3271{
3272 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3273 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3274 {
3275 return ipmi::responseInvalidFieldRequest();
3276 }
3277
3278 if (data.empty())
3279 {
3280 return ipmi::responseInvalidFieldRequest();
3281 }
3282 nlohmann::json json;
3283
3284 std::ifstream jsonStream(dimmOffsetFile);
3285 if (jsonStream.good())
3286 {
3287 json = nlohmann::json::parse(jsonStream, nullptr, false);
3288 if (json.is_discarded())
3289 {
3290 json = nlohmann::json();
3291 }
3292 jsonStream.close();
3293 }
3294
3295 std::string typeName;
3296 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3297 {
3298 typeName = dimmOffset::dimmPower;
3299 }
3300 else
3301 {
3302 typeName = dimmOffset::staticCltt;
3303 }
3304
3305 nlohmann::json& field = json[typeName];
3306
3307 for (const auto& [index, value] : data)
3308 {
3309 field[index] = value;
3310 }
3311
3312 for (nlohmann::json& val : field)
3313 {
3314 if (val == nullptr)
3315 {
3316 val = static_cast<uint8_t>(0);
3317 }
3318 }
3319
3320 std::ofstream output(dimmOffsetFile);
3321 if (!output.good())
3322 {
3323 std::cerr << "Error writing json file\n";
3324 return ipmi::responseResponseError();
3325 }
3326
3327 output << json.dump(4);
3328
3329 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3330 {
3331 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3332
Jason M. Bills0748c692022-09-08 15:34:08 -07003333 ipmi::DbusVariant offsets = field.get<std::vector<uint8_t>>();
James Feist63efafa2019-07-24 12:39:21 -07003334 auto call = bus->new_method_call(
3335 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3336 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3337 try
3338 {
3339 bus->call(call);
3340 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003341 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003342 {
3343 phosphor::logging::log<phosphor::logging::level::ERR>(
3344 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3345 phosphor::logging::entry("ERR=%s", e.what()));
3346 return ipmi::responseResponseError();
3347 }
3348 }
3349
3350 return ipmi::responseSuccess();
3351}
3352
3353ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3354{
James Feist63efafa2019-07-24 12:39:21 -07003355 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3356 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3357 {
3358 return ipmi::responseInvalidFieldRequest();
3359 }
3360
3361 std::ifstream jsonStream(dimmOffsetFile);
3362
3363 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3364 if (json.is_discarded())
3365 {
3366 std::cerr << "File error in " << dimmOffsetFile << "\n";
3367 return ipmi::responseResponseError();
3368 }
3369
3370 std::string typeName;
3371 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3372 {
3373 typeName = dimmOffset::dimmPower;
3374 }
3375 else
3376 {
3377 typeName = dimmOffset::staticCltt;
3378 }
3379
3380 auto it = json.find(typeName);
3381 if (it == json.end())
3382 {
3383 return ipmi::responseInvalidFieldRequest();
3384 }
3385
3386 if (it->size() <= index)
3387 {
3388 return ipmi::responseInvalidFieldRequest();
3389 }
3390
3391 uint8_t resp = it->at(index).get<uint8_t>();
3392 return ipmi::responseSuccess(resp);
3393}
3394
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003395namespace boot_options
3396{
3397
3398using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3399using IpmiValue = uint8_t;
3400constexpr auto ipmiDefault = 0;
3401
3402std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3403 {0x01, Source::Sources::Network},
3404 {0x02, Source::Sources::Disk},
3405 {0x05, Source::Sources::ExternalMedia},
3406 {0x0f, Source::Sources::RemovableMedia},
3407 {ipmiDefault, Source::Sources::Default}};
3408
3409std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003410 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003411
3412std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3413 {Source::Sources::Network, 0x01},
3414 {Source::Sources::Disk, 0x02},
3415 {Source::Sources::ExternalMedia, 0x05},
3416 {Source::Sources::RemovableMedia, 0x0f},
3417 {Source::Sources::Default, ipmiDefault}};
3418
3419std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003420 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003421
3422static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3423static constexpr auto bootSourceIntf =
3424 "xyz.openbmc_project.Control.Boot.Source";
3425static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3426static constexpr auto persistentObjPath =
3427 "/xyz/openbmc_project/control/host0/boot";
3428static constexpr auto oneTimePath =
3429 "/xyz/openbmc_project/control/host0/boot/one_time";
3430static constexpr auto bootSourceProp = "BootSource";
3431static constexpr auto bootModeProp = "BootMode";
3432static constexpr auto oneTimeBootEnableProp = "Enabled";
3433static constexpr auto httpBootMode =
3434 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3435
3436enum class BootOptionParameter : size_t
3437{
3438 setInProgress = 0x0,
3439 bootFlags = 0x5,
3440};
3441static constexpr uint8_t setComplete = 0x0;
3442static constexpr uint8_t setInProgress = 0x1;
3443static uint8_t transferStatus = setComplete;
3444static constexpr uint8_t setParmVersion = 0x01;
3445static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3446static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3447static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3448static constexpr uint8_t httpBoot = 0xd;
3449static constexpr uint8_t bootSourceMask = 0x3c;
3450
3451} // namespace boot_options
3452
3453ipmi::RspType<uint8_t, // version
3454 uint8_t, // param
3455 uint8_t, // data0, dependent on parameter
3456 std::optional<uint8_t> // data1, dependent on parameter
3457 >
3458 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3459{
3460 using namespace boot_options;
3461 uint8_t bootOption = 0;
3462
3463 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3464 {
3465 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3466 std::nullopt);
3467 }
3468
3469 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3470 {
3471 phosphor::logging::log<phosphor::logging::level::ERR>(
3472 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003473 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003474 }
3475
3476 try
3477 {
3478 auto oneTimeEnabled = false;
3479 // read one time Enabled property
3480 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3481 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3482 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3483 enabledIntf, oneTimeBootEnableProp);
3484 oneTimeEnabled = std::get<bool>(variant);
3485
3486 // get BootSource and BootMode properties
3487 // according to oneTimeEnable
3488 auto bootObjPath = oneTimePath;
3489 if (oneTimeEnabled == false)
3490 {
3491 bootObjPath = persistentObjPath;
3492 }
3493
3494 service = getService(*dbus, bootModeIntf, bootObjPath);
3495 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3496 bootModeProp);
3497
3498 auto bootMode =
3499 Mode::convertModesFromString(std::get<std::string>(variant));
3500
3501 service = getService(*dbus, bootSourceIntf, bootObjPath);
3502 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3503 bootSourceProp);
3504
3505 if (std::get<std::string>(variant) == httpBootMode)
3506 {
3507 bootOption = httpBoot;
3508 }
3509 else
3510 {
3511 auto bootSource = Source::convertSourcesFromString(
3512 std::get<std::string>(variant));
3513 bootOption = sourceDbusToIpmi.at(bootSource);
3514 if (Source::Sources::Default == bootSource)
3515 {
3516 bootOption = modeDbusToIpmi.at(bootMode);
3517 }
3518 }
3519
3520 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3521 : setParmBootFlagsValidPermanent;
3522 bootOption <<= 2; // shift for responseconstexpr
3523 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3524 bootOption);
3525 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003526 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003527 {
3528 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3529 return ipmi::responseResponseError();
3530 }
3531}
3532
3533ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3534 std::optional<uint8_t> bootOption)
3535{
3536 using namespace boot_options;
3537 auto oneTimeEnabled = false;
3538
Mike Jonesbc01d212022-06-16 12:41:33 -07003539 if (bootFlag == 0 && bootParam == 0)
3540 {
3541 phosphor::logging::log<phosphor::logging::level::ERR>(
3542 "Unsupported parameter");
3543 return ipmi::response(ccParameterNotSupported);
3544 }
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003545 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3546 {
3547 if (bootOption)
3548 {
3549 return ipmi::responseReqDataLenInvalid();
3550 }
3551
3552 if (transferStatus == setInProgress)
3553 {
3554 phosphor::logging::log<phosphor::logging::level::ERR>(
3555 "boot option set in progress!");
3556 return ipmi::responseResponseError();
3557 }
3558
3559 transferStatus = bootParam;
3560 return ipmi::responseSuccess();
3561 }
3562
3563 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3564 {
3565 phosphor::logging::log<phosphor::logging::level::ERR>(
3566 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003567 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003568 }
3569
3570 if (!bootOption)
3571 {
3572 return ipmi::responseReqDataLenInvalid();
3573 }
3574
3575 if (((bootOption.value() & bootSourceMask) >> 2) !=
3576 httpBoot) // not http boot, exit
3577 {
3578 phosphor::logging::log<phosphor::logging::level::ERR>(
3579 "wrong boot option parameter!");
3580 return ipmi::responseParmOutOfRange();
3581 }
3582
3583 try
3584 {
3585 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3586 setParmBootFlagsPermanent;
3587
3588 // read one time Enabled property
3589 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3590 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3591 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3592 enabledIntf, oneTimeBootEnableProp);
3593 oneTimeEnabled = std::get<bool>(variant);
3594
3595 /*
3596 * Check if the current boot setting is onetime or permanent, if the
3597 * request in the command is otherwise, then set the "Enabled"
3598 * property in one_time object path to 'True' to indicate onetime
3599 * and 'False' to indicate permanent.
3600 *
3601 * Once the onetime/permanent setting is applied, then the bootMode
3602 * and bootSource is updated for the corresponding object.
3603 */
3604 if (permanent == oneTimeEnabled)
3605 {
3606 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3607 oneTimeBootEnableProp, !permanent);
3608 }
3609
3610 // set BootSource and BootMode properties
3611 // according to oneTimeEnable or persistent
3612 auto bootObjPath = oneTimePath;
3613 if (oneTimeEnabled == false)
3614 {
3615 bootObjPath = persistentObjPath;
3616 }
3617 std::string bootMode =
3618 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3619 std::string bootSource = httpBootMode;
3620
3621 service = getService(*dbus, bootModeIntf, bootObjPath);
3622 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3623 bootMode);
3624
3625 service = getService(*dbus, bootSourceIntf, bootObjPath);
3626 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3627 bootSourceProp, bootSource);
3628 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003629 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003630 {
3631 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3632 return ipmi::responseResponseError();
3633 }
3634
3635 return ipmi::responseSuccess();
3636}
3637
Jason M. Bills0748c692022-09-08 15:34:08 -07003638using BasicVariantType = ipmi::DbusVariant;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003639using PropertyMapType =
3640 boost::container::flat_map<std::string, BasicVariantType>;
3641static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3642 "xyz.openbmc_project.Configuration.PSUPresence"};
3643int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3644 std::vector<uint64_t>& addrTable)
3645{
3646 boost::system::error_code ec;
3647 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3648 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3649 "/xyz/openbmc_project/object_mapper",
3650 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3651 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3652 if (ec)
3653 {
3654 phosphor::logging::log<phosphor::logging::level::ERR>(
3655 "Failed to set dbus property to cold redundancy");
3656 return -1;
3657 }
3658 for (const auto& object : subtree)
3659 {
3660 std::string pathName = object.first;
3661 for (const auto& serviceIface : object.second)
3662 {
3663 std::string serviceName = serviceIface.first;
3664
3665 ec.clear();
3666 PropertyMapType propMap =
3667 ctx->bus->yield_method_call<PropertyMapType>(
3668 ctx->yield, ec, serviceName, pathName,
3669 "org.freedesktop.DBus.Properties", "GetAll",
3670 "xyz.openbmc_project.Configuration.PSUPresence");
3671 if (ec)
3672 {
3673 phosphor::logging::log<phosphor::logging::level::ERR>(
3674 "Failed to set dbus property to cold redundancy");
3675 return -1;
3676 }
3677 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3678 auto psuAddress =
3679 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3680
3681 if (psuBus == nullptr || psuAddress == nullptr)
3682 {
3683 std::cerr << "error finding necessary "
3684 "entry in configuration\n";
3685 return -1;
3686 }
3687 bus = static_cast<uint8_t>(*psuBus);
3688 addrTable = *psuAddress;
3689 return 0;
3690 }
3691 }
3692 return -1;
3693}
3694
3695static const constexpr uint8_t addrOffset = 8;
3696static const constexpr uint8_t psuRevision = 0xd9;
3697static const constexpr uint8_t defaultPSUBus = 7;
3698// Second Minor, Primary Minor, Major
3699static const constexpr size_t verLen = 3;
3700ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3701{
3702 uint8_t bus = defaultPSUBus;
3703 std::vector<uint64_t> addrTable;
3704 std::vector<uint8_t> result;
3705 if (getPSUAddress(ctx, bus, addrTable))
3706 {
3707 std::cerr << "Failed to get PSU bus and address\n";
3708 return ipmi::responseResponseError();
3709 }
3710
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003711 for (const auto& targetAddr : addrTable)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003712 {
3713 std::vector<uint8_t> writeData = {psuRevision};
3714 std::vector<uint8_t> readBuf(verLen);
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003715 uint8_t addr = static_cast<uint8_t>(targetAddr) + addrOffset;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003716 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3717
3718 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3719 if (retI2C != ipmi::ccSuccess)
3720 {
3721 for (size_t idx = 0; idx < verLen; idx++)
3722 {
3723 result.emplace_back(0x00);
3724 }
3725 }
3726 else
3727 {
3728 for (const uint8_t& data : readBuf)
3729 {
3730 result.emplace_back(data);
3731 }
3732 }
3733 }
3734
3735 return ipmi::responseSuccess(result);
3736}
3737
srikanta mondal2030d7c2020-05-03 17:25:25 +00003738std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3739 const std::string& name)
3740{
3741 Value dbusValue = 0;
3742 std::string serviceName;
3743
3744 boost::system::error_code ec =
3745 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3746
3747 if (ec)
3748 {
3749 phosphor::logging::log<phosphor::logging::level::ERR>(
3750 "Failed to perform Multinode getService.");
3751 return std::nullopt;
3752 }
3753
3754 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3755 multiNodeIntf, name, dbusValue);
3756 if (ec)
3757 {
3758 phosphor::logging::log<phosphor::logging::level::ERR>(
3759 "Failed to perform Multinode get property");
3760 return std::nullopt;
3761 }
3762
3763 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3764 if (!multiNodeVal)
3765 {
3766 phosphor::logging::log<phosphor::logging::level::ERR>(
3767 "getMultiNodeInfoPresence: error to get multinode");
3768 return std::nullopt;
3769 }
3770 return *multiNodeVal;
3771}
3772
3773/** @brief implements OEM get reading command
3774 * @param domain ID
3775 * @param reading Type
3776 * - 00h = platform Power Consumption
3777 * - 01h = inlet Air Temp
3778 * - 02h = icc_TDC from PECI
3779 * @param reserved, write as 0000h
3780 *
3781 * @returns IPMI completion code plus response data
3782 * - response
3783 * - domain ID
3784 * - reading Type
3785 * - 00h = platform Power Consumption
3786 * - 01h = inlet Air Temp
3787 * - 02h = icc_TDC from PECI
3788 * - reading
3789 */
3790ipmi::RspType<uint4_t, // domain ID
3791 uint4_t, // reading Type
3792 uint16_t // reading Value
3793 >
3794 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3795 uint4_t readingType, uint16_t reserved)
3796{
3797 constexpr uint8_t platformPower = 0;
3798 constexpr uint8_t inletAirTemp = 1;
3799 constexpr uint8_t iccTdc = 2;
3800
3801 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3802 {
3803 return ipmi::responseInvalidFieldRequest();
3804 }
3805
3806 // This command should run only from multi-node product.
3807 // For all other platforms this command will return invalid.
3808
Patrick Williamsb37abfb2023-05-10 07:50:33 -05003809 std::optional<uint8_t> nodeInfo = getMultiNodeInfoPresence(ctx,
3810 "NodePresence");
srikanta mondal2030d7c2020-05-03 17:25:25 +00003811 if (!nodeInfo || !*nodeInfo)
3812 {
3813 return ipmi::responseInvalidCommand();
3814 }
3815
3816 uint16_t oemReadingValue = 0;
3817 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3818 {
3819 double value = 0;
3820 boost::system::error_code ec = ipmi::getDbusProperty(
3821 ctx, "xyz.openbmc_project.HwmonTempSensor",
3822 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3823 "xyz.openbmc_project.Sensor.Value", "Value", value);
3824 if (ec)
3825 {
3826 phosphor::logging::log<phosphor::logging::level::ERR>(
3827 "Failed to get BMC Get OEM temperature",
3828 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3829 return ipmi::responseUnspecifiedError();
3830 }
3831 // Take the Inlet temperature
3832 oemReadingValue = static_cast<uint16_t>(value);
3833 }
3834 else
3835 {
3836 phosphor::logging::log<phosphor::logging::level::ERR>(
3837 "Currently Get OEM Reading support only for Inlet Air Temp");
3838 return ipmi::responseParmOutOfRange();
3839 }
3840 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3841}
3842
AppaRao Puli28972062019-11-11 02:04:45 +05303843/** @brief implements the maximum size of
3844 * bridgeable messages used between KCS and
3845 * IPMB interfacesget security mode command.
3846 *
3847 * @returns IPMI completion code with following data
3848 * - KCS Buffer Size (In multiples of four bytes)
3849 * - IPMB Buffer Size (In multiples of four bytes)
3850 **/
3851ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3852{
3853 // for now this is hard coded; really this number is dependent on
3854 // the BMC kcs driver as well as the host kcs driver....
3855 // we can't know the latter.
3856 uint8_t kcsMaxBufferSize = 63 / 4;
3857 uint8_t ipmbMaxBufferSize = 128 / 4;
3858
3859 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3860}
3861
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003862ipmi::RspType<std::vector<uint8_t>>
3863 ipmiOEMReadPFRMailbox(ipmi::Context::ptr& ctx, const uint8_t readRegister,
3864 const uint8_t numOfBytes, uint8_t registerIdentifier)
3865{
3866 if (!ipmi::mailbox::i2cConfigLoaded)
3867 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003868 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003869 "Calling PFR Load Configuration Function to Get I2C Bus and Target "
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003870 "Address ");
3871
3872 ipmi::mailbox::loadPfrConfig(ctx, ipmi::mailbox::i2cConfigLoaded);
3873 }
3874
3875 if (!numOfBytes && !readRegister)
3876 {
3877 phosphor::logging::log<phosphor::logging::level::ERR>(
3878 "OEM IPMI command: Read & write count are 0 which is invalid ");
3879 return ipmi::responseInvalidFieldRequest();
3880 }
3881
3882 switch (registerIdentifier)
3883 {
3884 case ipmi::mailbox::registerType::fifoReadRegister:
3885 {
3886 // Check if readRegister is an FIFO read register
3887 if (registerIdentifier == 1)
3888 {
3889 if (ipmi::mailbox::readFifoReg.find(readRegister) ==
3890 ipmi::mailbox::readFifoReg.end())
3891 {
3892 phosphor::logging::log<phosphor::logging::level::ERR>(
3893 "OEM IPMI command: Register is not a Read FIFO ");
3894 return ipmi::responseInvalidFieldRequest();
3895 }
3896
3897 phosphor::logging::log<phosphor::logging::level::ERR>(
3898 "OEM IPMI command: Register is a Read FIFO ");
3899
3900 ipmi::mailbox::writefifo(ipmi::mailbox::provisioningCommand,
3901 readRegister);
3902 ipmi::mailbox::writefifo(ipmi::mailbox::triggerCommand,
3903 ipmi::mailbox::flushRead);
3904
3905 std::vector<uint8_t> writeData = {ipmi::mailbox::readFifo};
3906 std::vector<uint8_t> readBuf(1);
3907 std::vector<uint8_t> result;
3908
3909 for (int i = 0; i < numOfBytes; i++)
3910 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003911 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003912 ipmi::mailbox::targetAddr,
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003913 writeData, readBuf);
3914 if (ret != ipmi::ccSuccess)
3915 {
3916 return ipmi::response(ret);
3917 }
3918
3919 else
3920 {
3921 for (const uint8_t& data : readBuf)
3922 {
3923 result.emplace_back(data);
3924 }
3925 }
3926 }
3927
3928 return ipmi::responseSuccess(result);
3929 }
3930 }
3931
3932 case ipmi::mailbox::registerType::singleByteRegister:
3933 {
3934 phosphor::logging::log<phosphor::logging::level::ERR>(
3935 "OEM IPMI command: Register is a Single Byte Register ");
3936
3937 std::vector<uint8_t> writeData = {readRegister};
3938 std::vector<uint8_t> readBuf(numOfBytes);
3939
3940 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003941 ipmi::mailbox::targetAddr,
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003942 writeData, readBuf);
3943 if (ret != ipmi::ccSuccess)
3944 {
3945 return ipmi::response(ret);
3946 }
3947 return ipmi::responseSuccess(readBuf);
3948 }
3949
3950 default:
3951 {
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003952 phosphor::logging::log<phosphor::logging::level::ERR>(
3953 "OEM IPMI command: Register identifier is not valid.It should "
3954 "be 0 "
3955 "for Single Byte Register and 1 for FIFO Read Register");
3956
3957 return ipmi::responseInvalidFieldRequest();
3958 }
3959 }
3960}
3961
Jason M. Bills64796042018-10-03 16:51:55 -07003962static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003963{
3964 phosphor::logging::log<phosphor::logging::level::INFO>(
3965 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003966 ipmiPrintAndRegister(intel::netFnGeneral,
3967 intel::general::cmdGetChassisIdentifier, NULL,
3968 ipmiOEMGetChassisIdentifier,
3969 PRIVILEGE_USER); // get chassis identifier
3970
3971 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3972 NULL, ipmiOEMSetSystemGUID,
3973 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003974
3975 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003976 registerHandler(prioOemBase, intel::netFnGeneral,
3977 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3978 ipmiOEMDisableBMCSystemReset);
3979
Jason M. Billsb02bf092019-08-15 13:01:56 -07003980 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003981 registerHandler(prioOemBase, intel::netFnGeneral,
3982 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3983 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003984
Vernon Mauery98bbf692019-09-16 11:14:59 -07003985 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3986 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003987
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003988 registerHandler(prioOemBase, intel::netFnGeneral,
3989 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3990 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003991
Vernon Mauery98bbf692019-09-16 11:14:59 -07003992 ipmiPrintAndRegister(intel::netFnGeneral,
3993 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3994 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303995
Vernon Mauery98bbf692019-09-16 11:14:59 -07003996 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3997 intel::general::cmdSendEmbeddedFWUpdStatus,
3998 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303999
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05304000 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
4001 Privilege::Admin, ipmiOEMSlotIpmb);
4002
Vernon Mauery98bbf692019-09-16 11:14:59 -07004003 ipmiPrintAndRegister(intel::netFnGeneral,
4004 intel::general::cmdSetPowerRestoreDelay, NULL,
4005 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
4006
4007 ipmiPrintAndRegister(intel::netFnGeneral,
4008 intel::general::cmdGetPowerRestoreDelay, NULL,
4009 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
4010
4011 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4012 intel::general::cmdSetOEMUser2Activation,
4013 Privilege::Callback, ipmiOEMSetUser2Activation);
4014
4015 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4016 intel::general::cmdSetSpecialUserPassword,
4017 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05304018
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004019 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004020 registerHandler(prioOemBase, intel::netFnGeneral,
4021 intel::general::cmdGetProcessorErrConfig, Privilege::User,
4022 ipmiOEMGetProcessorErrConfig);
4023
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004024 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004025 registerHandler(prioOemBase, intel::netFnGeneral,
4026 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
4027 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004028
Vernon Mauery98bbf692019-09-16 11:14:59 -07004029 ipmiPrintAndRegister(intel::netFnGeneral,
4030 intel::general::cmdSetShutdownPolicy, NULL,
4031 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004032
Vernon Mauery98bbf692019-09-16 11:14:59 -07004033 ipmiPrintAndRegister(intel::netFnGeneral,
4034 intel::general::cmdGetShutdownPolicy, NULL,
4035 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004036
anil kumar appanaf945eee2019-09-25 23:29:11 +00004037 registerHandler(prioOemBase, intel::netFnGeneral,
4038 intel::general::cmdSetFanConfig, Privilege::User,
4039 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08004040
Vernon Mauery98bbf692019-09-16 11:14:59 -07004041 registerHandler(prioOemBase, intel::netFnGeneral,
4042 intel::general::cmdGetFanConfig, Privilege::User,
4043 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07004044
Vernon Mauery98bbf692019-09-16 11:14:59 -07004045 registerHandler(prioOemBase, intel::netFnGeneral,
4046 intel::general::cmdGetFanSpeedOffset, Privilege::User,
4047 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004048
Vernon Mauery98bbf692019-09-16 11:14:59 -07004049 registerHandler(prioOemBase, intel::netFnGeneral,
4050 intel::general::cmdSetFanSpeedOffset, Privilege::User,
4051 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004052
Vernon Mauery98bbf692019-09-16 11:14:59 -07004053 registerHandler(prioOemBase, intel::netFnGeneral,
4054 intel::general::cmdSetFscParameter, Privilege::User,
4055 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07004056
Vernon Mauery98bbf692019-09-16 11:14:59 -07004057 registerHandler(prioOemBase, intel::netFnGeneral,
4058 intel::general::cmdGetFscParameter, Privilege::User,
4059 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05304060
Vernon Mauery98bbf692019-09-16 11:14:59 -07004061 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4062 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
4063 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08004064
Vernon Mauery98bbf692019-09-16 11:14:59 -07004065 registerHandler(prioOemBase, intel::netFnGeneral,
4066 intel::general::cmdGetNmiStatus, Privilege::User,
4067 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08004068
Vernon Mauery98bbf692019-09-16 11:14:59 -07004069 registerHandler(prioOemBase, intel::netFnGeneral,
4070 intel::general::cmdSetNmiStatus, Privilege::Operator,
4071 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004072
Vernon Mauery98bbf692019-09-16 11:14:59 -07004073 registerHandler(prioOemBase, intel::netFnGeneral,
4074 intel::general::cmdGetEfiBootOptions, Privilege::User,
4075 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004076
Vernon Mauery98bbf692019-09-16 11:14:59 -07004077 registerHandler(prioOemBase, intel::netFnGeneral,
4078 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
4079 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304080
Vernon Mauery98bbf692019-09-16 11:14:59 -07004081 registerHandler(prioOemBase, intel::netFnGeneral,
4082 intel::general::cmdGetSecurityMode, Privilege::User,
4083 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304084
Vernon Mauery98bbf692019-09-16 11:14:59 -07004085 registerHandler(prioOemBase, intel::netFnGeneral,
4086 intel::general::cmdSetSecurityMode, Privilege::Admin,
4087 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004088
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00004089 registerHandler(prioOemBase, intel::netFnGeneral,
4090 intel::general::cmdGetLEDStatus, Privilege::Admin,
4091 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08004092
Vernon Mauery98bbf692019-09-16 11:14:59 -07004093 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
4094 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
4095 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
4096
4097 registerHandler(prioOemBase, intel::netFnGeneral,
4098 intel::general::cmdSetFaultIndication, Privilege::Operator,
4099 ipmiOEMSetFaultIndication);
4100
4101 registerHandler(prioOemBase, intel::netFnGeneral,
4102 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
4103 ipmiOEMSetCRConfig);
4104
4105 registerHandler(prioOemBase, intel::netFnGeneral,
4106 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
4107 ipmiOEMGetCRConfig);
4108
4109 registerHandler(prioOemBase, intel::netFnGeneral,
4110 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004111 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07004112
Vernon Mauery98bbf692019-09-16 11:14:59 -07004113 registerHandler(prioOemBase, intel::netFnGeneral,
4114 intel::general::cmdSetDimmOffset, Privilege::Operator,
4115 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07004116
Vernon Mauery98bbf692019-09-16 11:14:59 -07004117 registerHandler(prioOemBase, intel::netFnGeneral,
4118 intel::general::cmdGetDimmOffset, Privilege::Operator,
4119 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08004120
Cheng C Yang4e6ee152019-09-25 10:27:44 +08004121 registerHandler(prioOemBase, intel::netFnGeneral,
4122 intel::general::cmdGetPSUVersion, Privilege::User,
4123 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05304124
4125 registerHandler(prioOemBase, intel::netFnGeneral,
4126 intel::general::cmdGetBufferSize, Privilege::User,
4127 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00004128
4129 registerHandler(prioOemBase, intel::netFnGeneral,
4130 intel::general::cmdOEMGetReading, Privilege::User,
4131 ipmiOEMGetReading);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00004132
4133 registerHandler(prioOemBase, intel::netFnApp, intel::app::cmdPFRMailboxRead,
4134 Privilege::Admin, ipmiOEMReadPFRMailbox);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004135}
4136
4137} // namespace ipmi