blob: 11dab6f6880f92ca210803d62596db84a2a3ea4a [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 {
209
210 phosphor::logging::log<phosphor::logging::level::ERR>(
211 "Failed to fetch PFR object from dbus",
212 phosphor::logging::entry("INTERFACE=%s", sessionIntf),
213 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
214
215 return;
216 }
217
218 for (auto& softObject : objectTree)
219 {
220 const std::string& objPath = softObject.first;
221 const std::string& serviceName = softObject.second.begin()->first;
222 // PFR object found.. check for PFR support
223 ipmi::PropertyMap result;
224
225 ec = ipmi::getAllDbusProperties(ctx, serviceName, objPath, sessionIntf,
226 result);
227
228 if (ec)
229 {
230 phosphor::logging::log<phosphor::logging::level::ERR>(
231 "Failed to fetch pfr properties",
232 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
233 return;
234 }
235
236 const uint64_t* i2cBusNum = nullptr;
237 const uint64_t* address = nullptr;
238
239 for (const auto& [propName, propVariant] : result)
240 {
241
242 if (propName == "Address")
243 {
244 address = std::get_if<uint64_t>(&propVariant);
245 }
246 else if (propName == "Bus")
247 {
248 i2cBusNum = std::get_if<uint64_t>(&propVariant);
249 }
250 }
251
252 if ((address == nullptr) || (i2cBusNum == nullptr))
253 {
254 phosphor::logging::log<phosphor::logging::level::ERR>(
255 "Unable to read the pfr properties");
256 return;
257 }
258
259 bus = static_cast<int>(*i2cBusNum);
260 i2cBus = "/dev/i2c-" + std::to_string(bus);
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800261 targetAddr = static_cast<int>(*address);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000262
263 i2cConfigLoaded = true;
264 }
265}
266
267void writefifo(const uint8_t cmdReg, const uint8_t val)
268{
269 // Based on the spec, writing cmdReg to address val on this device, will
270 // trigger the write FIFO operation.
271 std::vector<uint8_t> writeData = {cmdReg, val};
272 std::vector<uint8_t> readBuf(0);
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800273 ipmi::Cc retI2C =
274 ipmi::i2cWriteRead(i2cBus, targetAddr, writeData, readBuf);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000275}
276
277} // namespace mailbox
278
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800279// Returns the Chassis Identifier (serial #)
280ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
281 ipmi_request_t request,
282 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700283 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800284 ipmi_context_t context)
285{
286 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700287 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800288 {
Jason M. Bills64796042018-10-03 16:51:55 -0700289 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800290 return IPMI_CC_REQ_DATA_LEN_INVALID;
291 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700292 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
293 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800294 {
Jason M. Bills64796042018-10-03 16:51:55 -0700295 *dataLen = serial.size(); // length will never exceed response length
296 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700298 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800299 return IPMI_CC_OK;
300 }
Jason M. Bills64796042018-10-03 16:51:55 -0700301 *dataLen = 0;
302 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800303}
304
305ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
306 ipmi_request_t request,
307 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700308 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800309{
310 static constexpr size_t safeBufferLength = 50;
311 char buf[safeBufferLength] = {0};
312 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
313
Jason M. Bills64796042018-10-03 16:51:55 -0700314 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 {
Jason M. Bills64796042018-10-03 16:51:55 -0700316 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800317 return IPMI_CC_REQ_DATA_LEN_INVALID;
318 }
319
Jason M. Bills64796042018-10-03 16:51:55 -0700320 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800321
322 snprintf(
323 buf, safeBufferLength,
324 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
325 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
326 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
327 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
328 Data->node3, Data->node2, Data->node1);
329 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
330 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800331
332 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
333 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700334 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
335 std::string service = getService(*dbus, intf, objpath);
336 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800337 return IPMI_CC_OK;
338}
339
Jason M. Billsb02bf092019-08-15 13:01:56 -0700340ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
341 uint7_t reserved1)
342{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000343 if (reserved1)
344 {
345 return ipmi::responseInvalidFieldRequest();
346 }
347
Jason M. Billsb02bf092019-08-15 13:01:56 -0700348 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
349
350 try
351 {
352 auto service =
353 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
354 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
355 bmcResetDisablesIntf, "ResetOnSMI",
356 !disableResetOnSMI);
357 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500358 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700359 {
360 phosphor::logging::log<phosphor::logging::level::ERR>(
361 "Failed to set BMC reset disables",
362 phosphor::logging::entry("EXCEPTION=%s", e.what()));
363 return ipmi::responseUnspecifiedError();
364 }
365
366 return ipmi::responseSuccess();
367}
368
369ipmi::RspType<bool, // disableResetOnSMI
370 uint7_t // reserved
371 >
372 ipmiOEMGetBMCResetDisables()
373{
374 bool disableResetOnSMI = true;
375
376 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
377 try
378 {
379 auto service =
380 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
381 Value variant =
382 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
383 bmcResetDisablesIntf, "ResetOnSMI");
384 disableResetOnSMI = !std::get<bool>(variant);
385 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500386 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700387 {
388 phosphor::logging::log<phosphor::logging::level::ERR>(
389 "Failed to get BMC reset disables",
390 phosphor::logging::entry("EXCEPTION=%s", e.what()));
391 return ipmi::responseUnspecifiedError();
392 }
393
394 return ipmi::responseSuccess(disableResetOnSMI, 0);
395}
396
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800397ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
398 ipmi_request_t request, ipmi_response_t response,
399 ipmi_data_len_t dataLen, ipmi_context_t context)
400{
401 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
402
Jason M. Bills64796042018-10-03 16:51:55 -0700403 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800404 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800405 *dataLen = 0;
406 return IPMI_CC_REQ_DATA_LEN_INVALID;
407 }
Jason M. Bills64796042018-10-03 16:51:55 -0700408 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000409 for (auto idChar : idString)
410 {
411 if (!std::isprint(static_cast<unsigned char>(idChar)))
412 {
413 phosphor::logging::log<phosphor::logging::level::ERR>(
414 "BIOS ID contains non printable character");
415 return IPMI_CC_INVALID_FIELD_REQUEST;
416 }
417 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800418
Vernon Mauery15419dd2019-05-24 09:40:30 -0700419 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000420 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
421 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800422 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800423 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
424 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700425 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800426 *dataLen = 1;
427 return IPMI_CC_OK;
428}
429
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000430bool getActiveHSCSoftwareVersionInfo(std::string& hscVersion, size_t hscNumber)
431{
432 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
433 try
434 {
435 std::string hsbpObjPath =
436 "/xyz/openbmc_project/software/HSBP_" + std::to_string(hscNumber);
437 auto service = getService(*dbus, biosVersionIntf, hsbpObjPath);
438 Value hscVersionValue =
439 getDbusProperty(*dbus, "xyz.openbmc_project.HsbpManager",
440 hsbpObjPath, biosVersionIntf, "Version");
441 hscVersion = std::get<std::string>(hscVersionValue);
442 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500443 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000444 {
445 phosphor::logging::log<phosphor::logging::level::INFO>(
446 "Failed to retrieve HSBP version information",
447 phosphor::logging::entry("HSBP Number=%d", hscNumber));
448 return false;
449 }
450 return true;
451}
452
453bool getHscVerInfo(ipmi::Context::ptr ctx, uint8_t& hsc0Major,
454 uint8_t& hsc0Minor, uint8_t& hsc1Major, uint8_t& hsc1Minor,
455 uint8_t& hsc2Major, uint8_t& hsc2Minor)
456{
457 std::string hscVersion;
458 std::array<uint8_t, 6> hscVersions{0};
459
460 for (size_t hscNumber = 1; hscNumber <= 3; hscNumber++)
461 {
462 if (!getActiveHSCSoftwareVersionInfo(hscVersion, hscNumber))
463 {
464 continue;
465 }
466 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?)");
467 constexpr size_t matchedPhosphor = 4;
468 std::smatch results;
469 // hscVersion = BOOT_VER.FPGA_VER.SECURITY_REVISION (Example: 00.02.01)
470 if (std::regex_match(hscVersion, results, pattern1))
471 {
472 // Major version is FPGA_VER and Minor version is SECURITY_REV
473 if (results.size() == matchedPhosphor)
474 {
475 int index = (hscNumber - 1) * 2;
476 hscVersions[index] =
477 static_cast<uint8_t>(std::stoi(results[2]));
478 hscVersions[index + 1] =
479 static_cast<uint8_t>(std::stoi(results[3]));
480 }
481 }
482 }
483 hsc0Major = hscVersions[0];
484 hsc0Minor = hscVersions[1];
485 hsc1Major = hscVersions[2];
486 hsc1Minor = hscVersions[3];
487 hsc2Major = hscVersions[4];
488 hsc2Minor = hscVersions[5];
489 return true;
490}
491
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530492bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
493 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800494{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800495 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530496 std::string bmcVersion;
497 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800498 {
499 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800500 }
501
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530502 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800503 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800504 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800505 MetaRevision revision = rev.value();
506 bmcMajor = revision.major;
507
508 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
509 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
510 }
511
512 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530513 std::string meVersion;
514 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800515 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800516 return false;
517 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530518 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
519 constexpr size_t matchedPhosphor = 6;
520 std::smatch results;
521 if (std::regex_match(meVersion, results, pattern1))
522 {
523 if (results.size() == matchedPhosphor)
524 {
525 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
Jayaprakash Mutyalad0657022021-08-26 21:18:08 +0000526 meMinor = static_cast<uint8_t>(std::stoi(results[2]) << 4 |
527 std::stoi(results[3]));
AppaRao Puli32825a22020-01-17 15:52:41 +0530528 }
529 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800530 return true;
531}
532
533ipmi::RspType<
534 std::variant<std::string,
535 std::tuple<uint8_t, std::array<uint8_t, 2>,
536 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
537 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
538 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530539 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
540 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530541 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800542{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800543 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
544 {
545 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800546 }
547
548 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800549 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800550 {
551 case OEMDevEntityType::biosId:
552 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530553 // Byte 2&3, Only used with selecting BIOS
554 if (!countToRead || !offset)
555 {
556 return ipmi::responseReqDataLenInvalid();
557 }
558
Vernon Mauery15419dd2019-05-24 09:40:30 -0700559 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800560 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000561 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800562 try
563 {
Yong Li2742b852019-12-16 14:55:11 +0800564 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000565 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800566 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700567 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530568 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800569 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800570 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800571 }
Jason M. Bills64796042018-10-03 16:51:55 -0700572 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530573 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700574 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530575 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700576 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800577 else
578 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530579 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800580 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800581
582 std::string readBuf = {0};
583 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530584 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800585 (readBuf.begin()));
586 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800587 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500588 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800589 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800590 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800591 }
592 }
593 break;
594
595 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800596 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530597 // Byte 2&3, Only used with selecting BIOS
598 if (countToRead || offset)
599 {
600 return ipmi::responseReqDataLenInvalid();
601 }
602
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800603 constexpr const size_t verLen = 2;
604 constexpr const size_t verTotalLen = 10;
605 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
606 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
607 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
608 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
609 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
610 // data0/1: BMC version number; data6/7: ME version number
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530611 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800612 {
613 return ipmi::responseUnspecifiedError();
614 }
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000615 if (!getHscVerInfo(ctx, hsc0Buf[0], hsc0Buf[1], hsc1Buf[0],
616 hsc1Buf[1], hsc2Buf[0], hsc2Buf[1]))
617 {
618 return ipmi::responseUnspecifiedError();
619 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800620 return ipmi::responseSuccess(
621 std::tuple<
622 uint8_t, std::array<uint8_t, verLen>,
623 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
624 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
625 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
626 }
627 break;
628
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800629 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800630 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530631 // Byte 2&3, Only used with selecting BIOS
632 if (countToRead || offset)
633 {
634 return ipmi::responseReqDataLenInvalid();
635 }
636
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800637 constexpr const size_t sdrLen = 2;
638 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
639 return ipmi::responseSuccess(
640 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
641 readBuf});
642 }
643 break;
644
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800645 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800646 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800647 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800648}
649
650ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
651 ipmi_request_t request, ipmi_response_t response,
652 ipmi_data_len_t dataLen, ipmi_context_t context)
653{
654 if (*dataLen != 0)
655 {
Jason M. Bills64796042018-10-03 16:51:55 -0700656 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800657 return IPMI_CC_REQ_DATA_LEN_INVALID;
658 }
659
660 *dataLen = 1;
661 uint8_t* res = reinterpret_cast<uint8_t*>(response);
662 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
663 // AIC is available so that BIOS will not timeout repeatly which leads to
664 // slow booting.
665 *res = 0; // Byte1=Count of SlotPosition/FruID records.
666 return IPMI_CC_OK;
667}
668
Jason M. Bills64796042018-10-03 16:51:55 -0700669ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
670 ipmi_request_t request,
671 ipmi_response_t response,
672 ipmi_data_len_t dataLen,
673 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800674{
Jason M. Bills64796042018-10-03 16:51:55 -0700675 GetPowerRestoreDelayRes* resp =
676 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
677
678 if (*dataLen != 0)
679 {
680 *dataLen = 0;
681 return IPMI_CC_REQ_DATA_LEN_INVALID;
682 }
683
Vernon Mauery15419dd2019-05-24 09:40:30 -0700684 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700685 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700686 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700687 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700688 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700689 powerRestoreDelayIntf, powerRestoreDelayProp);
690
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300691 uint64_t val = std::get<uint64_t>(variant);
692 val /= 1000000UL;
693 uint16_t delay = val;
Jason M. Bills64796042018-10-03 16:51:55 -0700694 resp->byteLSB = delay;
695 resp->byteMSB = delay >> 8;
696
697 *dataLen = sizeof(GetPowerRestoreDelayRes);
698
699 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800700}
701
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800702static uint8_t bcdToDec(uint8_t val)
703{
704 return ((val / 16 * 10) + (val % 16));
705}
706
707// Allows an update utility or system BIOS to send the status of an embedded
708// firmware update attempt to the BMC. After received, BMC will create a logging
709// record.
710ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
711 uint8_t majorRevision,
712 uint8_t minorRevision,
713 uint32_t auxInfo)
714{
715 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700716 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800717 target = (target & selEvtTargetMask) >> selEvtTargetShift;
718
719 /* make sure the status is 0, 1, or 2 as per the spec */
720 if (status > 2)
721 {
722 return ipmi::response(ipmi::ccInvalidFieldRequest);
723 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700724 /* make sure the target is 0, 1, 2, or 4 as per the spec */
725 if (target > 4 || target == 3)
726 {
727 return ipmi::response(ipmi::ccInvalidFieldRequest);
728 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800729 /*orignal OEM command is to record OEM SEL.
730 But openbmc does not support OEM SEL, so we redirect it to redfish event
731 logging. */
732 std::string buildInfo;
733 std::string action;
734 switch (FWUpdateTarget(target))
735 {
736 case FWUpdateTarget::targetBMC:
737 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700738 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800739 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
740 " BuildID: " + std::to_string(auxInfo);
741 buildInfo += std::to_string(auxInfo);
742 break;
743 case FWUpdateTarget::targetBIOS:
744 firmware = "BIOS";
745 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700746 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800747 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
748 " minor: " +
749 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
750 " ReleaseNumber: " + // ASCII encoded
751 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
752 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
753 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
754 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
755 break;
756 case FWUpdateTarget::targetME:
757 firmware = "ME";
758 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700759 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800760 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
761 " minor2: " +
762 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
763 " build1: " +
764 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
765 " build2: " +
766 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
767 break;
768 case FWUpdateTarget::targetOEMEWS:
769 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700770 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800771 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
772 " BuildID: " + std::to_string(auxInfo);
773 break;
774 }
775
Jason M. Billsdc249272019-04-03 09:58:40 -0700776 static const std::string openBMCMessageRegistryVersion("0.1");
777 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
778
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800779 switch (status)
780 {
781 case 0x0:
782 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700783 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800784 break;
785 case 0x1:
786 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700787 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800788 break;
789 case 0x2:
790 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700791 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800792 break;
793 default:
794 action = "unknown";
795 break;
796 }
797
Jason M. Billsdc249272019-04-03 09:58:40 -0700798 std::string firmwareInstanceStr =
799 firmware + " instance: " + std::to_string(instance);
800 std::string message("[firmware update] " + firmwareInstanceStr +
801 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800802
803 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700804 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
805 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
806 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800807 return ipmi::responseSuccess();
808}
809
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530810ipmi::RspType<uint8_t, std::vector<uint8_t>>
811 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
812 uint2_t slotNumber, uint3_t baseBoardSlotNum,
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800813 uint3_t riserSlotNum, uint2_t reserved2, uint8_t targetAddr,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530814 uint8_t netFn, uint8_t cmd,
815 std::optional<std::vector<uint8_t>> writeData)
816{
817 if (reserved1 || reserved2)
818 {
819 return ipmi::responseInvalidFieldRequest();
820 }
821
822 boost::system::error_code ec;
823 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
824 std::vector<uint8_t>>;
825 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
826 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
827 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
828 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
Matt Simmering80d4d5f2023-02-15 15:18:51 -0800829 static_cast<uint8_t>(baseBoardSlotNum), targetAddr, netFn, cmd,
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530830 *writeData);
831 if (ec)
832 {
833 phosphor::logging::log<phosphor::logging::level::ERR>(
834 "Failed to call dbus method SlotIpmbRequest");
835 return ipmi::responseUnspecifiedError();
836 }
837
838 std::vector<uint8_t> dataReceived(0);
839 int status = -1;
840 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
841
842 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
843
844 if (status)
845 {
846 phosphor::logging::log<phosphor::logging::level::ERR>(
847 "Failed to get response from SlotIpmbRequest");
848 return ipmi::responseResponseError();
849 }
850 return ipmi::responseSuccess(cc, dataReceived);
851}
852
Jason M. Bills64796042018-10-03 16:51:55 -0700853ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
854 ipmi_request_t request,
855 ipmi_response_t response,
856 ipmi_data_len_t dataLen,
857 ipmi_context_t context)
858{
859 SetPowerRestoreDelayReq* data =
860 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
861 uint16_t delay = 0;
862
863 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
864 {
865 *dataLen = 0;
866 return IPMI_CC_REQ_DATA_LEN_INVALID;
867 }
868 delay = data->byteMSB;
869 delay = (delay << 8) | data->byteLSB;
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300870 uint64_t val = delay * 1000000;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700871 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700872 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700873 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
874 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300875 powerRestoreDelayIntf, powerRestoreDelayProp, val);
Jason M. Bills64796042018-10-03 16:51:55 -0700876 *dataLen = 0;
877
878 return IPMI_CC_OK;
879}
880
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700881static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700882{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700883 static constexpr const char* cpuPresencePathPrefix =
884 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
885 static constexpr const char* cpuPresenceIntf =
886 "xyz.openbmc_project.Inventory.Item";
887 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
888 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
889 try
Jason M. Bills64796042018-10-03 16:51:55 -0700890 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700891 auto service =
892 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
893
894 ipmi::Value result = ipmi::getDbusProperty(
895 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
896 return std::get<bool>(result);
897 }
898 catch (const std::exception& e)
899 {
900 phosphor::logging::log<phosphor::logging::level::INFO>(
901 "Cannot find processor presence",
902 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
903 return false;
904 }
905}
906
907ipmi::RspType<bool, // CATERR Reset Enabled
908 bool, // ERR2 Reset Enabled
909 uint6_t, // reserved
910 uint8_t, // reserved, returns 0x3F
911 uint6_t, // CPU1 CATERR Count
912 uint2_t, // CPU1 Status
913 uint6_t, // CPU2 CATERR Count
914 uint2_t, // CPU2 Status
915 uint6_t, // CPU3 CATERR Count
916 uint2_t, // CPU3 Status
917 uint6_t, // CPU4 CATERR Count
918 uint2_t, // CPU4 Status
919 uint8_t // Crashdump Count
920 >
921 ipmiOEMGetProcessorErrConfig()
922{
923 bool resetOnCATERR = false;
924 bool resetOnERR2 = false;
925 uint6_t cpu1CATERRCount = 0;
926 uint6_t cpu2CATERRCount = 0;
927 uint6_t cpu3CATERRCount = 0;
928 uint6_t cpu4CATERRCount = 0;
929 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700930 uint2_t cpu1Status = cpuPresent("CPU_1")
931 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
932 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
933 uint2_t cpu2Status = cpuPresent("CPU_2")
934 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
935 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
936 uint2_t cpu3Status = cpuPresent("CPU_3")
937 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
938 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
939 uint2_t cpu4Status = cpuPresent("CPU_4")
940 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
941 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700942
943 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
944 try
945 {
946 auto service = ipmi::getService(*busp, processorErrConfigIntf,
947 processorErrConfigObjPath);
948
949 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
950 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
951 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
952 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
953 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
954 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
955 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
956 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
957 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
958 }
959 catch (const std::exception& e)
960 {
961 phosphor::logging::log<phosphor::logging::level::ERR>(
962 "Failed to fetch processor error config",
963 phosphor::logging::entry("ERROR=%s", e.what()));
964 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700965 }
966
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700967 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
968 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
969 cpu2Status, cpu3CATERRCount, cpu3Status,
970 cpu4CATERRCount, cpu4Status, crashdumpCount);
971}
Jason M. Bills64796042018-10-03 16:51:55 -0700972
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700973ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
974 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
975 std::optional<bool> clearCPUErrorCount,
976 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
977{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000978 if (reserved1 || reserved2)
979 {
980 return ipmi::responseInvalidFieldRequest();
981 }
982
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700983 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700984
985 try
986 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000987 if (reserved3.value_or(0))
988 {
989 return ipmi::responseInvalidFieldRequest();
990 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700991 auto service = ipmi::getService(*busp, processorErrConfigIntf,
992 processorErrConfigObjPath);
993 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
994 processorErrConfigIntf, "ResetOnCATERR",
995 resetOnCATERR);
996 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
997 processorErrConfigIntf, "ResetOnERR2",
998 resetOnERR2);
999 if (clearCPUErrorCount.value_or(false))
1000 {
1001 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001002 processorErrConfigIntf, "ErrorCountCPU1",
1003 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001004 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001005 processorErrConfigIntf, "ErrorCountCPU2",
1006 static_cast<uint8_t>(0));
1007 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1008 processorErrConfigIntf, "ErrorCountCPU3",
1009 static_cast<uint8_t>(0));
1010 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1011 processorErrConfigIntf, "ErrorCountCPU4",
1012 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001013 }
1014 if (clearCrashdumpCount.value_or(false))
1015 {
1016 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001017 processorErrConfigIntf, "CrashdumpCount",
1018 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001019 }
Jason M. Bills64796042018-10-03 16:51:55 -07001020 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001021 catch (const std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -07001022 {
Kuiying Wangbc546672018-11-23 15:41:05 +08001023 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001024 "Failed to set processor error config",
1025 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1026 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -07001027 }
1028
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001029 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -07001030}
1031
Yong Li703922d2018-11-06 13:25:31 +08001032ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1033 ipmi_request_t request,
1034 ipmi_response_t response,
1035 ipmi_data_len_t dataLen,
1036 ipmi_context_t context)
1037{
1038 GetOEMShutdownPolicyRes* resp =
1039 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
1040
1041 if (*dataLen != 0)
1042 {
1043 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +08001044 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +08001045 *dataLen = 0;
1046 return IPMI_CC_REQ_DATA_LEN_INVALID;
1047 }
1048
1049 *dataLen = 0;
1050
1051 try
1052 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001053 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +08001054 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001055 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
1056 Value variant = getDbusProperty(
1057 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
1058 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +08001059
1060 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1061 convertPolicyFromString(std::get<std::string>(variant)) ==
1062 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1063 NoShutdownOnOCOT)
1064 {
1065 resp->policy = 0;
1066 }
1067 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1068 convertPolicyFromString(std::get<std::string>(variant)) ==
1069 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1070 Policy::ShutdownOnOCOT)
1071 {
1072 resp->policy = 1;
1073 }
1074 else
1075 {
1076 phosphor::logging::log<phosphor::logging::level::ERR>(
1077 "oem_set_shutdown_policy: invalid property!",
1078 phosphor::logging::entry(
1079 "PROP=%s", std::get<std::string>(variant).c_str()));
1080 return IPMI_CC_UNSPECIFIED_ERROR;
1081 }
Yong Li703922d2018-11-06 13:25:31 +08001082 // TODO needs to check if it is multi-node products,
1083 // policy is only supported on node 3/4
1084 resp->policySupport = shutdownPolicySupported;
1085 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001086 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001087 {
1088 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1089 return IPMI_CC_UNSPECIFIED_ERROR;
1090 }
1091
1092 *dataLen = sizeof(GetOEMShutdownPolicyRes);
1093 return IPMI_CC_OK;
1094}
1095
1096ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1097 ipmi_request_t request,
1098 ipmi_response_t response,
1099 ipmi_data_len_t dataLen,
1100 ipmi_context_t context)
1101{
1102 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +08001103 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
1104 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1105 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +08001106
1107 // TODO needs to check if it is multi-node products,
1108 // policy is only supported on node 3/4
1109 if (*dataLen != 1)
1110 {
1111 phosphor::logging::log<phosphor::logging::level::ERR>(
1112 "oem_set_shutdown_policy: invalid input len!");
1113 *dataLen = 0;
1114 return IPMI_CC_REQ_DATA_LEN_INVALID;
1115 }
1116
1117 *dataLen = 0;
1118 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
1119 {
1120 phosphor::logging::log<phosphor::logging::level::ERR>(
1121 "oem_set_shutdown_policy: invalid input!");
1122 return IPMI_CC_INVALID_FIELD_REQUEST;
1123 }
1124
Yong Li0669d192019-05-06 14:01:46 +08001125 if (*req == noShutdownOnOCOT)
1126 {
1127 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1128 Policy::NoShutdownOnOCOT;
1129 }
1130 else
1131 {
1132 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1133 Policy::ShutdownOnOCOT;
1134 }
1135
Yong Li703922d2018-11-06 13:25:31 +08001136 try
1137 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001138 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +08001139 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001140 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +08001141 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001142 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +08001143 oemShutdownPolicyObjPathProp,
1144 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +08001145 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001146 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001147 {
1148 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1149 return IPMI_CC_UNSPECIFIED_ERROR;
1150 }
1151
1152 return IPMI_CC_OK;
1153}
1154
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301155/** @brief implementation for check the DHCP or not in IPv4
1156 * @param[in] Channel - Channel number
1157 * @returns true or false.
1158 */
1159static bool isDHCPEnabled(uint8_t Channel)
1160{
1161 try
1162 {
1163 auto ethdevice = getChannelName(Channel);
1164 if (ethdevice.empty())
1165 {
1166 return false;
1167 }
1168 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001169 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301170 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001171 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1172 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301173 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001174 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301175 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1176 {
1177 return true;
1178 }
1179 else
1180 {
1181 return false;
1182 }
1183 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001184 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301185 {
1186 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1187 return true;
1188 }
1189}
1190
1191/** @brief implementes for check the DHCP or not in IPv6
1192 * @param[in] Channel - Channel number
1193 * @returns true or false.
1194 */
1195static bool isDHCPIPv6Enabled(uint8_t Channel)
1196{
1197
1198 try
1199 {
1200 auto ethdevice = getChannelName(Channel);
1201 if (ethdevice.empty())
1202 {
1203 return false;
1204 }
1205 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001206 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301207 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001208 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1209 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301210 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001211 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301212 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1213 {
1214 return true;
1215 }
1216 else
1217 {
1218 return false;
1219 }
1220 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001221 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301222 {
1223 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1224 return true;
1225 }
1226}
1227
1228/** @brief implementes the creating of default new user
1229 * @param[in] userName - new username in 16 bytes.
1230 * @param[in] userPassword - new password in 20 bytes
1231 * @returns ipmi completion code.
1232 */
1233ipmi::RspType<> ipmiOEMSetUser2Activation(
1234 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001235 const SecureBuffer& userPassword)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301236{
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001237 if (userPassword.size() != ipmi::maxIpmi20PasswordSize)
1238 {
1239 return ipmi::responseReqDataLenInvalid();
1240 }
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301241 bool userState = false;
1242 // Check for System Interface not exist and LAN should be static
1243 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1244 {
Manish Baing440f62b2021-07-15 22:00:37 +00001245 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301246 try
1247 {
1248 getChannelInfo(channel, chInfo);
1249 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001250 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301251 {
1252 phosphor::logging::log<phosphor::logging::level::ERR>(
1253 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1254 phosphor::logging::entry("MSG: %s", e.description()));
1255 return ipmi::response(ipmi::ccUnspecifiedError);
1256 }
1257 if (chInfo.mediumType ==
1258 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1259 {
1260 phosphor::logging::log<phosphor::logging::level::ERR>(
1261 "ipmiOEMSetUser2Activation: system interface exist .");
1262 return ipmi::response(ipmi::ccCommandNotAvailable);
1263 }
1264 else
1265 {
1266
1267 if (chInfo.mediumType ==
1268 static_cast<uint8_t>(EChannelMediumType::lan8032))
1269 {
1270 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1271 {
1272 phosphor::logging::log<phosphor::logging::level::ERR>(
1273 "ipmiOEMSetUser2Activation: DHCP enabled .");
1274 return ipmi::response(ipmi::ccCommandNotAvailable);
1275 }
1276 }
1277 }
1278 }
1279 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1280 if (ipmi::ccSuccess ==
1281 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1282 {
1283 if (enabledUsers > 1)
1284 {
1285 phosphor::logging::log<phosphor::logging::level::ERR>(
1286 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1287 return ipmi::response(ipmi::ccCommandNotAvailable);
1288 }
1289 // Check the user 2 is enabled or not
1290 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1291 if (userState == true)
1292 {
1293 phosphor::logging::log<phosphor::logging::level::ERR>(
1294 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1295 return ipmi::response(ipmi::ccCommandNotAvailable);
1296 }
1297 }
1298 else
1299 {
1300 return ipmi::response(ipmi::ccUnspecifiedError);
1301 }
1302
1303#if BYTE_ORDER == LITTLE_ENDIAN
1304 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1305#endif
1306#if BYTE_ORDER == BIG_ENDIAN
1307 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1308#endif
1309
Vernon Mauery037cabd2020-05-14 12:16:01 -07001310 // ipmiUserSetUserName correctly handles char*, possibly non-null
1311 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001312 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1313 sizeof(userName));
1314 const std::string userNameRaw(
1315 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001316
Vernon Mauery037cabd2020-05-14 12:16:01 -07001317 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301318 {
1319 if (ipmi::ccSuccess ==
1320 ipmiUserSetUserPassword(
1321 ipmiDefaultUserId,
1322 reinterpret_cast<const char*>(userPassword.data())))
1323 {
1324 if (ipmi::ccSuccess ==
1325 ipmiUserSetPrivilegeAccess(
1326 ipmiDefaultUserId,
1327 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1328 privAccess, true))
1329 {
1330 phosphor::logging::log<phosphor::logging::level::INFO>(
1331 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001332
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301333 return ipmi::responseSuccess();
1334 }
1335 }
1336 // we need to delete the default user id which added in this command as
1337 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001338 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301339 phosphor::logging::log<phosphor::logging::level::ERR>(
1340 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1341 }
1342 else
1343 {
1344 phosphor::logging::log<phosphor::logging::level::ERR>(
1345 "ipmiOEMSetUser2Activation: Setting username failed.");
1346 }
1347
1348 return ipmi::response(ipmi::ccCommandNotAvailable);
1349}
1350
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301351/** @brief implementes executing the linux command
1352 * @param[in] linux command
1353 * @returns status
1354 */
1355
1356static uint8_t executeCmd(const char* path)
1357{
1358 boost::process::child execProg(path);
1359 execProg.wait();
1360
1361 int retCode = execProg.exit_code();
1362 if (retCode)
1363 {
1364 return ipmi::ccUnspecifiedError;
1365 }
1366 return ipmi::ccSuccess;
1367}
1368
1369/** @brief implementes ASD Security event logging
1370 * @param[in] Event message string
1371 * @param[in] Event Severity
1372 * @returns status
1373 */
1374
1375static void atScaleDebugEventlog(std::string msg, int severity)
1376{
1377 std::string eventStr = "OpenBMC.0.1." + msg;
1378 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1379 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1380 eventStr.c_str(), NULL);
1381}
1382
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301383/** @brief implementes setting password for special user
1384 * @param[in] specialUserIndex
1385 * @param[in] userPassword - new password in 20 bytes
1386 * @returns ipmi completion code.
1387 */
1388ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1389 uint8_t specialUserIndex,
1390 std::vector<uint8_t> userPassword)
1391{
1392 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301393 ipmi_ret_t status = ipmi::ccSuccess;
1394
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301395 try
1396 {
1397 getChannelInfo(ctx->channel, chInfo);
1398 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001399 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301400 {
1401 phosphor::logging::log<phosphor::logging::level::ERR>(
1402 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1403 phosphor::logging::entry("MSG: %s", e.description()));
1404 return ipmi::responseUnspecifiedError();
1405 }
1406 if (chInfo.mediumType !=
1407 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1408 {
1409 phosphor::logging::log<phosphor::logging::level::ERR>(
1410 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1411 "interface");
1412 return ipmi::responseCommandNotAvailable();
1413 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301414
1415 // 0 for root user and 1 for AtScaleDebug is allowed
1416 if (specialUserIndex >
1417 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301418 {
1419 phosphor::logging::log<phosphor::logging::level::ERR>(
1420 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1421 return ipmi::responseParmOutOfRange();
1422 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301423 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301424 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301425 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001426 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301427 if (userPassword.size() < minPasswordSizeRequired ||
1428 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1429 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001430 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301431 return ipmi::responseReqDataLenInvalid();
1432 }
1433 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1434 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001435 // Clear sensitive data
1436 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301437 if (specialUserIndex ==
1438 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1439 {
1440 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1441
1442 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1443 }
1444 else
1445 {
1446 status = ipmiSetSpecialUserPassword("root", passwd);
1447 }
1448 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301449 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301450 else
1451 {
1452 if (specialUserIndex ==
1453 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1454 {
1455 status = executeCmd("passwd -d root");
1456 }
1457 else
1458 {
1459
1460 status = executeCmd("passwd -d asdbg");
1461
1462 if (status == 0)
1463 {
1464 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1465 LOG_INFO);
1466 }
1467 }
1468 return ipmi::response(status);
1469 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301470}
1471
Kuiying Wang45f04982018-12-26 09:23:08 +08001472namespace ledAction
1473{
1474using namespace sdbusplus::xyz::openbmc_project::Led::server;
1475std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001476 {Physical::Action::Off, 0},
1477 {Physical::Action::On, 2},
1478 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001479
1480std::map<uint8_t, std::string> offsetObjPath = {
1481 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1482
1483} // namespace ledAction
1484
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001485int8_t getLEDState(sdbusplus::bus_t& bus, const std::string& intf,
Kuiying Wang45f04982018-12-26 09:23:08 +08001486 const std::string& objPath, uint8_t& state)
1487{
1488 try
1489 {
1490 std::string service = getService(bus, intf, objPath);
1491 Value stateValue =
1492 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001493 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001494 state = ledAction::actionDbusToIpmi.at(
1495 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1496 convertActionFromString(strState));
1497 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001498 catch (const sdbusplus::exception_t& e)
Kuiying Wang45f04982018-12-26 09:23:08 +08001499 {
1500 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1501 return -1;
1502 }
1503 return 0;
1504}
1505
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001506ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001507{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001508 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001509 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001510 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001511 for (auto it = ledAction::offsetObjPath.begin();
1512 it != ledAction::offsetObjPath.end(); ++it)
1513 {
1514 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001515 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001516 {
1517 phosphor::logging::log<phosphor::logging::level::ERR>(
1518 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001519 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001520 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001521 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001522 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001523 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001524}
1525
Yong Li23737fe2019-02-19 08:49:55 +08001526ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1527 ipmi_request_t request,
1528 ipmi_response_t response,
1529 ipmi_data_len_t dataLen,
1530 ipmi_context_t context)
1531{
1532 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1533 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1534
1535 if (*dataLen == 0)
1536 {
1537 phosphor::logging::log<phosphor::logging::level::ERR>(
1538 "CfgHostSerial: invalid input len!",
1539 phosphor::logging::entry("LEN=%d", *dataLen));
1540 return IPMI_CC_REQ_DATA_LEN_INVALID;
1541 }
1542
1543 switch (req->command)
1544 {
1545 case getHostSerialCfgCmd:
1546 {
1547 if (*dataLen != 1)
1548 {
1549 phosphor::logging::log<phosphor::logging::level::ERR>(
1550 "CfgHostSerial: invalid input len!");
1551 *dataLen = 0;
1552 return IPMI_CC_REQ_DATA_LEN_INVALID;
1553 }
1554
1555 *dataLen = 0;
1556
1557 boost::process::ipstream is;
1558 std::vector<std::string> data;
1559 std::string line;
1560 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1561 boost::process::std_out > is);
1562
1563 while (c1.running() && std::getline(is, line) && !line.empty())
1564 {
1565 data.push_back(line);
1566 }
1567
1568 c1.wait();
1569 if (c1.exit_code())
1570 {
1571 phosphor::logging::log<phosphor::logging::level::ERR>(
1572 "CfgHostSerial:: error on execute",
1573 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1574 // Using the default value
1575 *resp = 0;
1576 }
1577 else
1578 {
1579 if (data.size() != 1)
1580 {
1581 phosphor::logging::log<phosphor::logging::level::ERR>(
1582 "CfgHostSerial:: error on read env");
1583 return IPMI_CC_UNSPECIFIED_ERROR;
1584 }
1585 try
1586 {
1587 unsigned long tmp = std::stoul(data[0]);
1588 if (tmp > std::numeric_limits<uint8_t>::max())
1589 {
1590 throw std::out_of_range("Out of range");
1591 }
1592 *resp = static_cast<uint8_t>(tmp);
1593 }
1594 catch (const std::invalid_argument& e)
1595 {
1596 phosphor::logging::log<phosphor::logging::level::ERR>(
1597 "invalid config ",
1598 phosphor::logging::entry("ERR=%s", e.what()));
1599 return IPMI_CC_UNSPECIFIED_ERROR;
1600 }
1601 catch (const std::out_of_range& e)
1602 {
1603 phosphor::logging::log<phosphor::logging::level::ERR>(
1604 "out_of_range config ",
1605 phosphor::logging::entry("ERR=%s", e.what()));
1606 return IPMI_CC_UNSPECIFIED_ERROR;
1607 }
1608 }
1609
1610 *dataLen = 1;
1611 break;
1612 }
1613 case setHostSerialCfgCmd:
1614 {
1615 if (*dataLen != sizeof(CfgHostSerialReq))
1616 {
1617 phosphor::logging::log<phosphor::logging::level::ERR>(
1618 "CfgHostSerial: invalid input len!");
1619 *dataLen = 0;
1620 return IPMI_CC_REQ_DATA_LEN_INVALID;
1621 }
1622
1623 *dataLen = 0;
1624
1625 if (req->parameter > HostSerialCfgParamMax)
1626 {
1627 phosphor::logging::log<phosphor::logging::level::ERR>(
1628 "CfgHostSerial: invalid input!");
1629 return IPMI_CC_INVALID_FIELD_REQUEST;
1630 }
1631
1632 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1633 std::to_string(req->parameter));
1634
1635 c1.wait();
1636 if (c1.exit_code())
1637 {
1638 phosphor::logging::log<phosphor::logging::level::ERR>(
1639 "CfgHostSerial:: error on execute",
1640 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1641 return IPMI_CC_UNSPECIFIED_ERROR;
1642 }
1643 break;
1644 }
1645 default:
1646 phosphor::logging::log<phosphor::logging::level::ERR>(
1647 "CfgHostSerial: invalid input!");
1648 *dataLen = 0;
1649 return IPMI_CC_INVALID_FIELD_REQUEST;
1650 }
1651
1652 return IPMI_CC_OK;
1653}
1654
James Feist91244a62019-02-19 15:04:54 -08001655constexpr const char* thermalModeInterface =
1656 "xyz.openbmc_project.Control.ThermalMode";
1657constexpr const char* thermalModePath =
1658 "/xyz/openbmc_project/control/thermal_mode";
1659
1660bool getFanProfileInterface(
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001661 sdbusplus::bus_t& bus,
Jason M. Bills0748c692022-09-08 15:34:08 -07001662 boost::container::flat_map<std::string, ipmi::DbusVariant>& resp)
James Feist91244a62019-02-19 15:04:54 -08001663{
1664 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1665 "GetAll");
1666 call.append(thermalModeInterface);
1667 try
1668 {
1669 auto data = bus.call(call);
1670 data.read(resp);
1671 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001672 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001673 {
1674 phosphor::logging::log<phosphor::logging::level::ERR>(
1675 "getFanProfileInterface: can't get thermal mode!",
1676 phosphor::logging::entry("ERR=%s", e.what()));
1677 return false;
1678 }
1679 return true;
1680}
1681
anil kumar appanaf945eee2019-09-25 23:29:11 +00001682/**@brief implements the OEM set fan config.
1683 * @param selectedFanProfile - fan profile to enable
1684 * @param reserved1
1685 * @param performanceMode - Performance/Acoustic mode
1686 * @param reserved2
1687 * @param setPerformanceMode - set Performance/Acoustic mode
1688 * @param setFanProfile - set fan profile
1689 *
1690 * @return IPMI completion code.
1691 **/
1692ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1693
1694 uint2_t reserved1, bool performanceMode,
1695 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301696 bool setFanProfile,
1697 std::optional<uint8_t> dimmGroupId,
1698 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001699{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001700 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001701 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001702 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001703 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301704
1705 if (dimmGroupId)
1706 {
1707 if (*dimmGroupId >= maxCPUNum)
1708 {
1709 return ipmi::responseInvalidFieldRequest();
1710 }
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001711 if (!cpuPresent("cpu" + std::to_string(*dimmGroupId)))
Joshi-Mansi619186d2020-01-27 19:16:03 +05301712 {
1713 return ipmi::responseInvalidFieldRequest();
1714 }
1715 }
1716
James Feist91244a62019-02-19 15:04:54 -08001717 // todo: tell bios to only send first 2 bytes
Jason M. Bills0748c692022-09-08 15:34:08 -07001718 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001719 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1720 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001721 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001722 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001723 }
1724
1725 std::vector<std::string>* supported =
1726 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1727 if (supported == nullptr)
1728 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001729 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001730 }
1731 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001732 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001733 {
James Feist91244a62019-02-19 15:04:54 -08001734 if (performanceMode)
1735 {
1736
1737 if (std::find(supported->begin(), supported->end(),
1738 "Performance") != supported->end())
1739 {
1740 mode = "Performance";
1741 }
1742 }
1743 else
1744 {
James Feist91244a62019-02-19 15:04:54 -08001745 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1746 supported->end())
1747 {
1748 mode = "Acoustic";
1749 }
1750 }
1751 if (mode.empty())
1752 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001753 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001754 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001755
1756 try
1757 {
1758 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1759 thermalModeInterface, "Current", mode);
1760 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001761 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001762 {
1763 phosphor::logging::log<phosphor::logging::level::ERR>(
1764 "ipmiOEMSetFanConfig: can't set thermal mode!",
1765 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1766 return ipmi::responseResponseError();
1767 }
James Feist91244a62019-02-19 15:04:54 -08001768 }
1769
anil kumar appanaf945eee2019-09-25 23:29:11 +00001770 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001771}
1772
James Feist5b693632019-07-09 09:06:09 -07001773ipmi::RspType<uint8_t, // profile support map
1774 uint8_t, // fan control profile enable
1775 uint8_t, // flags
1776 uint32_t // dimm presence bit map
1777 >
1778 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001779{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301780 if (dimmGroupId >= maxCPUNum)
1781 {
1782 return ipmi::responseInvalidFieldRequest();
1783 }
1784
Snehalatha Venkatesh6224dec2023-01-24 11:28:53 +00001785 bool cpuStatus = cpuPresent("cpu" + std::to_string(dimmGroupId));
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301786
1787 if (!cpuStatus)
1788 {
1789 return ipmi::responseInvalidFieldRequest();
1790 }
1791
Jason M. Bills0748c692022-09-08 15:34:08 -07001792 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
James Feist91244a62019-02-19 15:04:54 -08001793
Vernon Mauery15419dd2019-05-24 09:40:30 -07001794 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1795 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001796 {
James Feist5b693632019-07-09 09:06:09 -07001797 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001798 }
1799
1800 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1801
1802 if (current == nullptr)
1803 {
1804 phosphor::logging::log<phosphor::logging::level::ERR>(
1805 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001806 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001807 }
1808 bool performance = (*current == "Performance");
1809
James Feist5b693632019-07-09 09:06:09 -07001810 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001811 if (performance)
1812 {
James Feist5b693632019-07-09 09:06:09 -07001813 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001814 }
1815
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001816 constexpr uint8_t fanControlDefaultProfile = 0x80;
1817 constexpr uint8_t fanControlProfileState = 0x00;
1818 constexpr uint32_t dimmPresenceBitmap = 0x00;
1819
1820 return ipmi::responseSuccess(fanControlDefaultProfile,
1821 fanControlProfileState, flags,
1822 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001823}
James Feist5f957ca2019-03-14 15:33:55 -07001824constexpr const char* cfmLimitSettingPath =
1825 "/xyz/openbmc_project/control/cfm_limit";
1826constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001827constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001828constexpr const size_t legacyPCHSensorNumber = 0x22;
1829constexpr const char* exitAirPathName = "Exit_Air";
1830constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001831constexpr const char* pidConfigurationIface =
1832 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001833
James Feist09f6b602019-08-08 11:30:03 -07001834static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001835{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001836 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001837 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001838 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1839 "/xyz/openbmc_project/object_mapper",
1840 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001841
James Feistacc8a4e2019-04-02 14:23:57 -07001842 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001843 std::string path;
1844 GetSubTreeType resp;
1845 try
1846 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001847 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001848 reply.read(resp);
1849 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001850 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001851 {
1852 phosphor::logging::log<phosphor::logging::level::ERR>(
1853 "ipmiOEMGetFscParameter: mapper error");
1854 };
James Feist09f6b602019-08-08 11:30:03 -07001855 auto config =
1856 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1857 return pair.first.find(name) != std::string::npos;
1858 });
James Feistfaa4f222019-03-21 16:21:55 -07001859 if (config != resp.end())
1860 {
1861 path = std::move(config->first);
1862 }
1863 return path;
1864}
James Feist5f957ca2019-03-14 15:33:55 -07001865
James Feistacc8a4e2019-04-02 14:23:57 -07001866// flat map to make alphabetical
1867static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1868{
1869 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001870 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001871 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001872 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1873 "/xyz/openbmc_project/object_mapper",
1874 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001875
1876 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1877 GetSubTreeType resp;
1878
1879 try
1880 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001881 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001882 reply.read(resp);
1883 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001884 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001885 {
1886 phosphor::logging::log<phosphor::logging::level::ERR>(
1887 "getFanConfigPaths: mapper error");
1888 };
1889 for (const auto& [path, objects] : resp)
1890 {
1891 if (objects.empty())
1892 {
1893 continue; // should be impossible
1894 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001895
1896 try
1897 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001898 ret.emplace(path,
1899 getAllDbusProperties(*dbus, objects[0].first, path,
1900 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001901 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001902 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001903 {
1904 phosphor::logging::log<phosphor::logging::level::ERR>(
1905 "getPidConfigs: can't get DbusProperties!",
1906 phosphor::logging::entry("ERR=%s", e.what()));
1907 }
James Feistacc8a4e2019-04-02 14:23:57 -07001908 }
1909 return ret;
1910}
1911
1912ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1913{
1914 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1915 if (data.empty())
1916 {
1917 return ipmi::responseResponseError();
1918 }
1919 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1920 for (const auto& [_, pid] : data)
1921 {
1922 auto findClass = pid.find("Class");
1923 if (findClass == pid.end())
1924 {
1925 phosphor::logging::log<phosphor::logging::level::ERR>(
1926 "ipmiOEMGetFscParameter: found illegal pid "
1927 "configurations");
1928 return ipmi::responseResponseError();
1929 }
1930 std::string type = std::get<std::string>(findClass->second);
1931 if (type == "fan")
1932 {
1933 auto findOutLimit = pid.find("OutLimitMin");
1934 if (findOutLimit == pid.end())
1935 {
1936 phosphor::logging::log<phosphor::logging::level::ERR>(
1937 "ipmiOEMGetFscParameter: found illegal pid "
1938 "configurations");
1939 return ipmi::responseResponseError();
1940 }
1941 // get the min out of all the offsets
1942 minOffset = std::min(
1943 minOffset,
1944 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1945 }
1946 }
1947 if (minOffset == std::numeric_limits<uint8_t>::max())
1948 {
1949 phosphor::logging::log<phosphor::logging::level::ERR>(
1950 "ipmiOEMGetFscParameter: found no fan configurations!");
1951 return ipmi::responseResponseError();
1952 }
1953
1954 return ipmi::responseSuccess(minOffset);
1955}
1956
1957ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1958{
Manish Baingbaa579f2021-10-08 22:30:32 +00001959 constexpr uint8_t maxFanSpeedOffset = 100;
1960 if (offset > maxFanSpeedOffset)
1961 {
1962 phosphor::logging::log<phosphor::logging::level::ERR>(
1963 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1964 return ipmi::responseInvalidFieldRequest();
1965 }
James Feistacc8a4e2019-04-02 14:23:57 -07001966 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1967 if (data.empty())
1968 {
1969
1970 phosphor::logging::log<phosphor::logging::level::ERR>(
1971 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1972 return ipmi::responseResponseError();
1973 }
1974
Vernon Mauery15419dd2019-05-24 09:40:30 -07001975 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001976 bool found = false;
1977 for (const auto& [path, pid] : data)
1978 {
1979 auto findClass = pid.find("Class");
1980 if (findClass == pid.end())
1981 {
1982
1983 phosphor::logging::log<phosphor::logging::level::ERR>(
1984 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1985 "configurations");
1986 return ipmi::responseResponseError();
1987 }
1988 std::string type = std::get<std::string>(findClass->second);
1989 if (type == "fan")
1990 {
1991 auto findOutLimit = pid.find("OutLimitMin");
1992 if (findOutLimit == pid.end())
1993 {
1994
1995 phosphor::logging::log<phosphor::logging::level::ERR>(
1996 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1997 "configurations");
1998 return ipmi::responseResponseError();
1999 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07002000 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07002001 path, pidConfigurationIface, "OutLimitMin",
2002 static_cast<double>(offset));
2003 found = true;
2004 }
2005 }
2006 if (!found)
2007 {
2008 phosphor::logging::log<phosphor::logging::level::ERR>(
2009 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
2010 return ipmi::responseResponseError();
2011 }
2012
2013 return ipmi::responseSuccess();
2014}
2015
2016ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
2017 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07002018{
2019 constexpr const size_t disableLimiting = 0x0;
2020
Vernon Mauery15419dd2019-05-24 09:40:30 -07002021 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002022 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002023 {
James Feist09f6b602019-08-08 11:30:03 -07002024 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07002025 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07002026 {
James Feist09f6b602019-08-08 11:30:03 -07002027 pathName = exitAirPathName;
2028 }
2029 else if (param1 == legacyPCHSensorNumber)
2030 {
2031 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07002032 }
2033 else
2034 {
James Feistacc8a4e2019-04-02 14:23:57 -07002035 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002036 }
James Feist09f6b602019-08-08 11:30:03 -07002037 std::string path = getConfigPath(pathName);
2038 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
2039 pidConfigurationIface, "SetPoint",
2040 static_cast<double>(param2));
2041 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07002042 }
James Feistacc8a4e2019-04-02 14:23:57 -07002043 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002044 {
James Feistacc8a4e2019-04-02 14:23:57 -07002045 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07002046
2047 // must be greater than 50 based on eps
2048 if (cfm < 50 && cfm != disableLimiting)
2049 {
James Feistacc8a4e2019-04-02 14:23:57 -07002050 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002051 }
2052
2053 try
2054 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002055 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07002056 cfmLimitIface, "Limit",
2057 static_cast<double>(cfm));
2058 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002059 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002060 {
2061 phosphor::logging::log<phosphor::logging::level::ERR>(
2062 "ipmiOEMSetFscParameter: can't set cfm setting!",
2063 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002064 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002065 }
James Feistacc8a4e2019-04-02 14:23:57 -07002066 return ipmi::responseSuccess();
2067 }
2068 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2069 {
2070 constexpr const size_t maxDomainCount = 8;
2071 uint8_t requestedDomainMask = param1;
2072 boost::container::flat_map data = getPidConfigs();
2073 if (data.empty())
2074 {
2075
2076 phosphor::logging::log<phosphor::logging::level::ERR>(
2077 "ipmiOEMSetFscParameter: found no pid configurations!");
2078 return ipmi::responseResponseError();
2079 }
2080 size_t count = 0;
2081 for (const auto& [path, pid] : data)
2082 {
2083 auto findClass = pid.find("Class");
2084 if (findClass == pid.end())
2085 {
2086
2087 phosphor::logging::log<phosphor::logging::level::ERR>(
2088 "ipmiOEMSetFscParameter: found illegal pid "
2089 "configurations");
2090 return ipmi::responseResponseError();
2091 }
2092 std::string type = std::get<std::string>(findClass->second);
2093 if (type == "fan")
2094 {
2095 if (requestedDomainMask & (1 << count))
2096 {
2097 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002098 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07002099 pidConfigurationIface, "OutLimitMax",
2100 static_cast<double>(param2));
2101 }
2102 count++;
2103 }
2104 }
2105 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07002106 }
2107 else
2108 {
2109 // todo other command parts possibly
2110 // tcontrol is handled in peci now
2111 // fan speed offset not implemented yet
2112 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002113 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002114 }
2115}
2116
James Feistacc8a4e2019-04-02 14:23:57 -07002117ipmi::RspType<
2118 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2119 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002120{
James Feist09f6b602019-08-08 11:30:03 -07002121 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002122
Vernon Mauery15419dd2019-05-24 09:40:30 -07002123 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002124 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002125 {
James Feistacc8a4e2019-04-02 14:23:57 -07002126 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002127 {
James Feistacc8a4e2019-04-02 14:23:57 -07002128 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002129 }
2130
James Feist09f6b602019-08-08 11:30:03 -07002131 std::string pathName;
2132
2133 if (*param == legacyExitAirSensorNumber)
2134 {
2135 pathName = exitAirPathName;
2136 }
2137 else if (*param == legacyPCHSensorNumber)
2138 {
2139 pathName = pchPathName;
2140 }
2141 else
James Feistfaa4f222019-03-21 16:21:55 -07002142 {
James Feistacc8a4e2019-04-02 14:23:57 -07002143 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002144 }
James Feist09f6b602019-08-08 11:30:03 -07002145
2146 uint8_t setpoint = legacyDefaultSetpoint;
2147 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002148 if (path.size())
2149 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002150 Value val = ipmi::getDbusProperty(
2151 *dbus, "xyz.openbmc_project.EntityManager", path,
2152 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002153 setpoint = std::floor(std::get<double>(val) + 0.5);
2154 }
2155
2156 // old implementation used to return the "default" and current, we
2157 // don't make the default readily available so just make both the
2158 // same
James Feistfaa4f222019-03-21 16:21:55 -07002159
James Feistacc8a4e2019-04-02 14:23:57 -07002160 return ipmi::responseSuccess(
2161 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002162 }
James Feistacc8a4e2019-04-02 14:23:57 -07002163 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2164 {
2165 constexpr const size_t maxDomainCount = 8;
2166
2167 if (!param)
2168 {
2169 return ipmi::responseReqDataLenInvalid();
2170 }
2171 uint8_t requestedDomain = *param;
2172 if (requestedDomain >= maxDomainCount)
2173 {
2174 return ipmi::responseInvalidFieldRequest();
2175 }
2176
2177 boost::container::flat_map data = getPidConfigs();
2178 if (data.empty())
2179 {
2180 phosphor::logging::log<phosphor::logging::level::ERR>(
2181 "ipmiOEMGetFscParameter: found no pid configurations!");
2182 return ipmi::responseResponseError();
2183 }
2184 size_t count = 0;
2185 for (const auto& [_, pid] : data)
2186 {
2187 auto findClass = pid.find("Class");
2188 if (findClass == pid.end())
2189 {
2190 phosphor::logging::log<phosphor::logging::level::ERR>(
2191 "ipmiOEMGetFscParameter: found illegal pid "
2192 "configurations");
2193 return ipmi::responseResponseError();
2194 }
2195 std::string type = std::get<std::string>(findClass->second);
2196 if (type == "fan")
2197 {
2198 if (requestedDomain == count)
2199 {
2200 auto findOutLimit = pid.find("OutLimitMax");
2201 if (findOutLimit == pid.end())
2202 {
2203 phosphor::logging::log<phosphor::logging::level::ERR>(
2204 "ipmiOEMGetFscParameter: found illegal pid "
2205 "configurations");
2206 return ipmi::responseResponseError();
2207 }
2208
2209 return ipmi::responseSuccess(
2210 static_cast<uint8_t>(std::floor(
2211 std::get<double>(findOutLimit->second) + 0.5)));
2212 }
2213 else
2214 {
2215 count++;
2216 }
2217 }
2218 }
2219
2220 return ipmi::responseInvalidFieldRequest();
2221 }
2222 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002223 {
2224
2225 /*
2226 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002227 previous behavior didn't seem to prevent this, ignore the check for
2228 now.
James Feist5f957ca2019-03-14 15:33:55 -07002229
James Feistacc8a4e2019-04-02 14:23:57 -07002230 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002231 {
2232 phosphor::logging::log<phosphor::logging::level::ERR>(
2233 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002234 return IPMI_CC_REQ_DATA_LEN_INVALID;
2235 }
2236 */
2237 Value cfmLimit;
2238 Value cfmMaximum;
2239 try
2240 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002241 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002242 cfmLimitSettingPath, cfmLimitIface,
2243 "Limit");
2244 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002245 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002246 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2247 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002248 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002249 {
2250 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002251 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002252 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002253 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002254 }
2255
James Feistacc8a4e2019-04-02 14:23:57 -07002256 double cfmMax = std::get<double>(cfmMaximum);
2257 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002258
James Feistacc8a4e2019-04-02 14:23:57 -07002259 cfmLim = std::floor(cfmLim + 0.5);
2260 cfmMax = std::floor(cfmMax + 0.5);
2261 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2262 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002263
James Feistacc8a4e2019-04-02 14:23:57 -07002264 return ipmi::responseSuccess(
2265 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002266 }
James Feistacc8a4e2019-04-02 14:23:57 -07002267
James Feist5f957ca2019-03-14 15:33:55 -07002268 else
2269 {
2270 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002271 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002272 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002273 }
2274}
2275
Jason M. Bills0748c692022-09-08 15:34:08 -07002276using crConfigVariant = ipmi::DbusVariant;
Cheng C Yang773703a2019-08-15 09:41:11 +08002277
2278int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2279 const crConfigVariant& value,
2280 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2281{
2282 boost::system::error_code ec;
2283 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002284 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002285 "/xyz/openbmc_project/control/power_supply_redundancy",
2286 "org.freedesktop.DBus.Properties", "Set",
2287 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2288 if (ec)
2289 {
2290 phosphor::logging::log<phosphor::logging::level::ERR>(
2291 "Failed to set dbus property to cold redundancy");
2292 return -1;
2293 }
2294
2295 return 0;
2296}
2297
Kuiying Wange45333a2020-07-22 22:06:37 +08002298int getCRConfig(
2299 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2300 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2301 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002302{
2303 boost::system::error_code ec;
2304 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002305 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002306 "/xyz/openbmc_project/control/power_supply_redundancy",
2307 "org.freedesktop.DBus.Properties", "Get",
2308 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2309 if (ec)
2310 {
2311 phosphor::logging::log<phosphor::logging::level::ERR>(
2312 "Failed to get dbus property to cold redundancy");
2313 return -1;
2314 }
2315 return 0;
2316}
2317
2318uint8_t getPSUCount(void)
2319{
2320 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2321 ipmi::Value num;
2322 try
2323 {
2324 num = ipmi::getDbusProperty(
2325 *dbus, "xyz.openbmc_project.PSURedundancy",
2326 "/xyz/openbmc_project/control/power_supply_redundancy",
2327 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2328 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002329 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002330 {
2331 phosphor::logging::log<phosphor::logging::level::ERR>(
2332 "Failed to get PSUNumber property from dbus interface");
2333 return 0;
2334 }
2335 uint8_t* pNum = std::get_if<uint8_t>(&num);
2336 if (!pNum)
2337 {
2338 phosphor::logging::log<phosphor::logging::level::ERR>(
2339 "Error to get PSU Number");
2340 return 0;
2341 }
2342 return *pNum;
2343}
2344
2345bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2346{
2347 if (conf.size() < num)
2348 {
2349 phosphor::logging::log<phosphor::logging::level::ERR>(
2350 "Invalid PSU Ranking");
2351 return false;
2352 }
2353 std::set<uint8_t> confSet;
2354 for (uint8_t i = 0; i < num; i++)
2355 {
2356 if (conf[i] > num)
2357 {
2358 phosphor::logging::log<phosphor::logging::level::ERR>(
2359 "PSU Ranking is larger than current PSU number");
2360 return false;
2361 }
2362 confSet.emplace(conf[i]);
2363 }
2364
2365 if (confSet.size() != num)
2366 {
2367 phosphor::logging::log<phosphor::logging::level::ERR>(
2368 "duplicate PSU Ranking");
2369 return false;
2370 }
2371 return true;
2372}
2373
2374enum class crParameter
2375{
2376 crStatus = 0,
2377 crFeature = 1,
2378 rotationFeature = 2,
2379 rotationAlgo = 3,
2380 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002381 numOfPSU = 5,
2382 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002383};
2384
2385constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2386static const constexpr uint32_t oneDay = 0x15180;
2387static const constexpr uint32_t oneMonth = 0xf53700;
2388static const constexpr uint8_t userSpecific = 0x01;
2389static const constexpr uint8_t crSetCompleted = 0;
2390ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2391 uint8_t parameter,
2392 ipmi::message::Payload& payload)
2393{
2394 switch (static_cast<crParameter>(parameter))
2395 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002396 case crParameter::rotationFeature:
2397 {
2398 uint8_t param1;
2399 if (payload.unpack(param1) || !payload.fullyUnpacked())
2400 {
2401 return ipmi::responseReqDataLenInvalid();
2402 }
2403 // Rotation Enable can only be true or false
2404 if (param1 > 1)
2405 {
2406 return ipmi::responseInvalidFieldRequest();
2407 }
2408 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2409 {
2410 return ipmi::responseResponseError();
2411 }
2412 break;
2413 }
2414 case crParameter::rotationAlgo:
2415 {
2416 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2417 std::string algoName;
2418 uint8_t param1;
2419 if (payload.unpack(param1))
2420 {
2421 return ipmi::responseReqDataLenInvalid();
2422 }
2423 switch (param1)
2424 {
2425 case 0:
2426 algoName = "xyz.openbmc_project.Control."
2427 "PowerSupplyRedundancy.Algo.bmcSpecific";
2428 break;
2429 case 1:
2430 algoName = "xyz.openbmc_project.Control."
2431 "PowerSupplyRedundancy.Algo.userSpecific";
2432 break;
2433 default:
2434 return ipmi::responseInvalidFieldRequest();
2435 }
2436 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2437 {
2438 return ipmi::responseResponseError();
2439 }
2440
2441 uint8_t numberOfPSU = getPSUCount();
2442 if (!numberOfPSU)
2443 {
2444 return ipmi::responseResponseError();
2445 }
2446 std::vector<uint8_t> rankOrder;
2447
2448 if (param1 == userSpecific)
2449 {
2450 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2451 {
2452 ipmi::responseReqDataLenInvalid();
2453 }
Yong Li83315132019-10-23 17:42:24 +08002454 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002455 {
2456 return ipmi::responseReqDataLenInvalid();
2457 }
2458
2459 if (!validateCRAlgo(rankOrder, numberOfPSU))
2460 {
2461 return ipmi::responseInvalidFieldRequest();
2462 }
2463 }
2464 else
2465 {
2466 if (rankOrder.size() > 0)
2467 {
2468 return ipmi::responseReqDataLenInvalid();
2469 }
2470 for (uint8_t i = 1; i <= numberOfPSU; i++)
2471 {
2472 rankOrder.emplace_back(i);
2473 }
2474 }
2475 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2476 {
2477 return ipmi::responseResponseError();
2478 }
2479 break;
2480 }
2481 case crParameter::rotationPeriod:
2482 {
2483 // Minimum Rotation period is One day (86400 seconds) and Max
2484 // Rotation Period is 6 month (0xf53700 seconds)
2485 uint32_t period;
2486 if (payload.unpack(period) || !payload.fullyUnpacked())
2487 {
2488 return ipmi::responseReqDataLenInvalid();
2489 }
2490 if ((period < oneDay) || (period > oneMonth))
2491 {
2492 return ipmi::responseInvalidFieldRequest();
2493 }
2494 if (setCRConfig(ctx, "PeriodOfRotation", period))
2495 {
2496 return ipmi::responseResponseError();
2497 }
2498 break;
2499 }
2500 default:
2501 {
2502 return ipmi::response(ccParameterNotSupported);
2503 }
2504 }
2505
Cheng C Yang773703a2019-08-15 09:41:11 +08002506 return ipmi::responseSuccess(crSetCompleted);
2507}
2508
Yong Li83315132019-10-23 17:42:24 +08002509ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002510 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2511{
2512 crConfigVariant value;
2513 switch (static_cast<crParameter>(parameter))
2514 {
2515 case crParameter::crStatus:
2516 {
2517 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2518 {
2519 return ipmi::responseResponseError();
2520 }
2521 std::string* pStatus = std::get_if<std::string>(&value);
2522 if (!pStatus)
2523 {
2524 phosphor::logging::log<phosphor::logging::level::ERR>(
2525 "Error to get ColdRedundancyStatus property");
2526 return ipmi::responseResponseError();
2527 }
2528 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2529 auto status =
2530 server::PowerSupplyRedundancy::convertStatusFromString(
2531 *pStatus);
2532 switch (status)
2533 {
2534 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002535 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002536 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002537
2538 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002539 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002540 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002541 default:
2542 phosphor::logging::log<phosphor::logging::level::ERR>(
2543 "Error to get valid status");
2544 return ipmi::responseResponseError();
2545 }
2546 }
2547 case crParameter::crFeature:
2548 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002549 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002550 {
2551 return ipmi::responseResponseError();
2552 }
2553 bool* pResponse = std::get_if<bool>(&value);
2554 if (!pResponse)
2555 {
2556 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002557 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002558 return ipmi::responseResponseError();
2559 }
2560
Cheng C Yangf41e3342019-09-10 04:47:23 +08002561 return ipmi::responseSuccess(parameter,
2562 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002563 }
2564 case crParameter::rotationFeature:
2565 {
2566 if (getCRConfig(ctx, "RotationEnabled", value))
2567 {
2568 return ipmi::responseResponseError();
2569 }
2570 bool* pResponse = std::get_if<bool>(&value);
2571 if (!pResponse)
2572 {
2573 phosphor::logging::log<phosphor::logging::level::ERR>(
2574 "Error to get RotationEnabled property");
2575 return ipmi::responseResponseError();
2576 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002577 return ipmi::responseSuccess(parameter,
2578 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002579 }
2580 case crParameter::rotationAlgo:
2581 {
2582 if (getCRConfig(ctx, "RotationAlgorithm", value))
2583 {
2584 return ipmi::responseResponseError();
2585 }
2586
2587 std::string* pAlgo = std::get_if<std::string>(&value);
2588 if (!pAlgo)
2589 {
2590 phosphor::logging::log<phosphor::logging::level::ERR>(
2591 "Error to get RotationAlgorithm property");
2592 return ipmi::responseResponseError();
2593 }
Yong Li83315132019-10-23 17:42:24 +08002594 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002595 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2596 auto algo =
2597 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002598
Cheng C Yang773703a2019-08-15 09:41:11 +08002599 switch (algo)
2600 {
2601 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002602 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002603 break;
2604 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002605 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002606 break;
2607 default:
2608 phosphor::logging::log<phosphor::logging::level::ERR>(
2609 "Error to get valid algo");
2610 return ipmi::responseResponseError();
2611 }
2612
2613 if (getCRConfig(ctx, "RotationRankOrder", value))
2614 {
2615 return ipmi::responseResponseError();
2616 }
2617 std::vector<uint8_t>* pResponse =
2618 std::get_if<std::vector<uint8_t>>(&value);
2619 if (!pResponse)
2620 {
2621 phosphor::logging::log<phosphor::logging::level::ERR>(
2622 "Error to get RotationRankOrder property");
2623 return ipmi::responseResponseError();
2624 }
Yong Li83315132019-10-23 17:42:24 +08002625
Cheng C Yang773703a2019-08-15 09:41:11 +08002626 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002627 std::back_inserter(response));
2628
Cheng C Yangf41e3342019-09-10 04:47:23 +08002629 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002630 }
2631 case crParameter::rotationPeriod:
2632 {
2633 if (getCRConfig(ctx, "PeriodOfRotation", value))
2634 {
2635 return ipmi::responseResponseError();
2636 }
2637 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2638 if (!pResponse)
2639 {
2640 phosphor::logging::log<phosphor::logging::level::ERR>(
2641 "Error to get RotationAlgorithm property");
2642 return ipmi::responseResponseError();
2643 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002644 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002645 }
2646 case crParameter::numOfPSU:
2647 {
2648 uint8_t numberOfPSU = getPSUCount();
2649 if (!numberOfPSU)
2650 {
2651 return ipmi::responseResponseError();
2652 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002653 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002654 }
Yong Li19445ab2019-12-20 18:25:29 +08002655 case crParameter::rotationRankOrderEffective:
2656 {
2657 if (getCRConfig(ctx, "RotationRankOrder", value,
2658 "xyz.openbmc_project.PSURedundancy"))
2659 {
2660 return ipmi::responseResponseError();
2661 }
2662 std::vector<uint8_t>* pResponse =
2663 std::get_if<std::vector<uint8_t>>(&value);
2664 if (!pResponse)
2665 {
2666 phosphor::logging::log<phosphor::logging::level::ERR>(
2667 "Error to get effective RotationRankOrder property");
2668 return ipmi::responseResponseError();
2669 }
2670 return ipmi::responseSuccess(parameter, *pResponse);
2671 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002672 default:
2673 {
2674 return ipmi::response(ccParameterNotSupported);
2675 }
2676 }
2677}
2678
Zhu, Yungebe560b02019-04-21 21:19:21 -04002679ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2680 uint8_t faultState,
2681 uint8_t faultGroup,
2682 std::array<uint8_t, 8>& ledStateData)
2683{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002684 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2685 static const std::array<std::string, maxFaultType> faultNames = {
2686 "faultFan", "faultTemp", "faultPower",
2687 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002688
2689 constexpr uint8_t maxFaultSource = 0x4;
2690 constexpr uint8_t skipLEDs = 0xFF;
2691 constexpr uint8_t pinSize = 64;
2692 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002693 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002694
Zhikui Rence4e73f2019-12-06 13:59:47 -08002695 // same pin names need to be defined in dts file
2696 static const std::array<std::array<std::string, groupSize>, groupNum>
2697 faultLedPinNames = {{
2698 "LED_CPU1_CH1_DIMM1_FAULT",
2699 "LED_CPU1_CH1_DIMM2_FAULT",
2700 "LED_CPU1_CH2_DIMM1_FAULT",
2701 "LED_CPU1_CH2_DIMM2_FAULT",
2702 "LED_CPU1_CH3_DIMM1_FAULT",
2703 "LED_CPU1_CH3_DIMM2_FAULT",
2704 "LED_CPU1_CH4_DIMM1_FAULT",
2705 "LED_CPU1_CH4_DIMM2_FAULT",
2706 "LED_CPU1_CH5_DIMM1_FAULT",
2707 "LED_CPU1_CH5_DIMM2_FAULT",
2708 "LED_CPU1_CH6_DIMM1_FAULT",
2709 "LED_CPU1_CH6_DIMM2_FAULT",
2710 "",
2711 "",
2712 "",
2713 "", // end of group1
2714 "LED_CPU2_CH1_DIMM1_FAULT",
2715 "LED_CPU2_CH1_DIMM2_FAULT",
2716 "LED_CPU2_CH2_DIMM1_FAULT",
2717 "LED_CPU2_CH2_DIMM2_FAULT",
2718 "LED_CPU2_CH3_DIMM1_FAULT",
2719 "LED_CPU2_CH3_DIMM2_FAULT",
2720 "LED_CPU2_CH4_DIMM1_FAULT",
2721 "LED_CPU2_CH4_DIMM2_FAULT",
2722 "LED_CPU2_CH5_DIMM1_FAULT",
2723 "LED_CPU2_CH5_DIMM2_FAULT",
2724 "LED_CPU2_CH6_DIMM1_FAULT",
2725 "LED_CPU2_CH6_DIMM2_FAULT",
2726 "",
2727 "",
2728 "",
2729 "", // endof group2
2730 "LED_CPU3_CH1_DIMM1_FAULT",
2731 "LED_CPU3_CH1_DIMM2_FAULT",
2732 "LED_CPU3_CH2_DIMM1_FAULT",
2733 "LED_CPU3_CH2_DIMM2_FAULT",
2734 "LED_CPU3_CH3_DIMM1_FAULT",
2735 "LED_CPU3_CH3_DIMM2_FAULT",
2736 "LED_CPU3_CH4_DIMM1_FAULT",
2737 "LED_CPU3_CH4_DIMM2_FAULT",
2738 "LED_CPU3_CH5_DIMM1_FAULT",
2739 "LED_CPU3_CH5_DIMM2_FAULT",
2740 "LED_CPU3_CH6_DIMM1_FAULT",
2741 "LED_CPU3_CH6_DIMM2_FAULT",
2742 "",
2743 "",
2744 "",
2745 "", // end of group3
2746 "LED_CPU4_CH1_DIMM1_FAULT",
2747 "LED_CPU4_CH1_DIMM2_FAULT",
2748 "LED_CPU4_CH2_DIMM1_FAULT",
2749 "LED_CPU4_CH2_DIMM2_FAULT",
2750 "LED_CPU4_CH3_DIMM1_FAULT",
2751 "LED_CPU4_CH3_DIMM2_FAULT",
2752 "LED_CPU4_CH4_DIMM1_FAULT",
2753 "LED_CPU4_CH4_DIMM2_FAULT",
2754 "LED_CPU4_CH5_DIMM1_FAULT",
2755 "LED_CPU4_CH5_DIMM2_FAULT",
2756 "LED_CPU4_CH6_DIMM1_FAULT",
2757 "LED_CPU4_CH6_DIMM2_FAULT",
2758 "",
2759 "",
2760 "",
2761 "", // end of group4
2762 "LED_FAN1_FAULT",
2763 "LED_FAN2_FAULT",
2764 "LED_FAN3_FAULT",
2765 "LED_FAN4_FAULT",
2766 "LED_FAN5_FAULT",
2767 "LED_FAN6_FAULT",
2768 "LED_FAN7_FAULT",
2769 "LED_FAN8_FAULT",
2770 "",
2771 "",
2772 "",
2773 "",
2774 "",
2775 "",
2776 "",
2777 "" // end of group5
2778 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002779
Zhikui Rence4e73f2019-12-06 13:59:47 -08002780 // Validate the source, fault type --
2781 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2782 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2783 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2784 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2785 // definition differs based on fault type (Byte 2)
2786 // Type Fan=> Group: 0=FanGroupID, FF-not used
2787 // Byte 5-11 00h, not used
2788 // Byte12 FanLedState [7:0]-Fans 7:0
2789 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2790 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2791 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2792 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2793 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2794 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2795 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2796 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002797 if ((sourceId >= maxFaultSource) ||
2798 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2799 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2800 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2801 {
2802 return ipmi::responseParmOutOfRange();
2803 }
2804
Zhikui Rence4e73f2019-12-06 13:59:47 -08002805 size_t pinGroupOffset = 0;
2806 size_t pinGroupMax = pinSize / groupSize;
2807 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002808 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002809 pinGroupOffset = 4;
2810 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002811 }
2812
2813 switch (RemoteFaultType(faultType))
2814 {
2815 case (RemoteFaultType::fan):
2816 case (RemoteFaultType::memory):
2817 {
2818 if (faultGroup == skipLEDs)
2819 {
2820 return ipmi::responseSuccess();
2821 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002822 // calculate led state bit filed count, each byte has 8bits
2823 // the maximum bits will be 8 * 8 bits
2824 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002825
2826 // assemble ledState
2827 uint64_t ledState = 0;
2828 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002829 for (int i = 0; i < sizeof(ledStateData); i++)
2830 {
2831 ledState = (uint64_t)(ledState << 8);
2832 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2833 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002834 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002835
Zhikui Rence4e73f2019-12-06 13:59:47 -08002836 for (int group = 0; group < pinGroupMax; group++)
2837 {
2838 for (int i = 0; i < groupSize; i++)
2839 { // skip non-existing pins
2840 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2841 {
2842 continue;
2843 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002844
Zhikui Rence4e73f2019-12-06 13:59:47 -08002845 gpiod::line line = gpiod::find_line(
2846 faultLedPinNames[group + pinGroupOffset][i]);
2847 if (!line)
2848 {
2849 phosphor::logging::log<phosphor::logging::level::ERR>(
2850 "Not Find Led Gpio Device!",
2851 phosphor::logging::entry(
2852 "DEVICE=%s",
2853 faultLedPinNames[group + pinGroupOffset][i]
2854 .c_str()));
2855 hasError = true;
2856 continue;
2857 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002858
Zhikui Rence4e73f2019-12-06 13:59:47 -08002859 bool activeHigh =
2860 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2861 try
2862 {
2863 line.request(
2864 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2865 activeHigh
2866 ? 0
2867 : gpiod::line_request::FLAG_ACTIVE_LOW});
2868 line.set_value(ledStateBits[i + group * groupSize]);
2869 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002870 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002871 {
2872 phosphor::logging::log<phosphor::logging::level::ERR>(
2873 "Error write Led Gpio Device!",
2874 phosphor::logging::entry(
2875 "DEVICE=%s",
2876 faultLedPinNames[group + pinGroupOffset][i]
2877 .c_str()));
2878 hasError = true;
2879 continue;
2880 }
2881 } // for int i
2882 }
2883 if (hasError)
2884 {
2885 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002886 }
2887 break;
2888 }
2889 default:
2890 {
2891 // now only support two fault types
2892 return ipmi::responseParmOutOfRange();
2893 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002894 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002895 return ipmi::responseSuccess();
2896}
2897
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302898ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2899{
2900 uint8_t prodId = 0;
2901 try
2902 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002903 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302904 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002905 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302906 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2907 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002908 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302909 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2910 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302911 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2912 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002913 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302914 {
2915 phosphor::logging::log<phosphor::logging::level::ERR>(
2916 "ipmiOEMReadBoardProductId: Product ID read failed!",
2917 phosphor::logging::entry("ERR=%s", e.what()));
2918 }
2919 return ipmi::responseSuccess(prodId);
2920}
2921
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302922/** @brief implements the get security mode command
2923 * @param ctx - ctx pointer
2924 *
2925 * @returns IPMI completion code with following data
2926 * - restriction mode value - As specified in
2927 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2928 * - special mode value - As specified in
2929 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2930 */
2931ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2932{
2933 namespace securityNameSpace =
2934 sdbusplus::xyz::openbmc_project::Control::Security::server;
2935 uint8_t restrictionModeValue = 0;
2936 uint8_t specialModeValue = 0;
2937
2938 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07002939 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07002940 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302941 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2942 restricionModeProperty);
2943 if (ec)
2944 {
2945 phosphor::logging::log<phosphor::logging::level::ERR>(
2946 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2947 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2948 return ipmi::responseUnspecifiedError();
2949 }
2950 restrictionModeValue = static_cast<uint8_t>(
2951 securityNameSpace::RestrictionMode::convertModesFromString(
2952 std::get<std::string>(varRestrMode)));
Jason M. Bills0748c692022-09-08 15:34:08 -07002953 auto varSpecialMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
2954 ctx->yield, ec, specialModeService, specialModeBasePath,
2955 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2956 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302957 if (ec)
2958 {
2959 phosphor::logging::log<phosphor::logging::level::ERR>(
2960 "ipmiGetSecurityMode: failed to get SpecialMode property",
2961 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2962 // fall through, let us not worry about SpecialMode property, which is
2963 // not required in user scenario
2964 }
2965 else
2966 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302967 specialModeValue = static_cast<uint8_t>(
2968 securityNameSpace::SpecialMode::convertModesFromString(
2969 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302970 }
2971 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2972}
2973
2974/** @brief implements the set security mode command
2975 * Command allows to upgrade the restriction mode and won't allow
2976 * to downgrade from system interface
2977 * @param ctx - ctx pointer
2978 * @param restrictionMode - restriction mode value to be set.
2979 *
2980 * @returns IPMI completion code
2981 */
2982ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302983 uint8_t restrictionMode,
2984 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302985{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302986#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2987 if (specialMode)
2988 {
2989 return ipmi::responseReqDataLenInvalid();
2990 }
2991#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302992 namespace securityNameSpace =
2993 sdbusplus::xyz::openbmc_project::Control::Security::server;
2994
2995 ChannelInfo chInfo;
2996 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2997 {
2998 phosphor::logging::log<phosphor::logging::level::ERR>(
2999 "ipmiSetSecurityMode: Failed to get Channel Info",
3000 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
3001 return ipmi::responseUnspecifiedError();
3002 }
3003 auto reqMode =
3004 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
3005
3006 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
3007 (reqMode >
3008 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
3009 {
3010 return ipmi::responseInvalidFieldRequest();
3011 }
3012
3013 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07003014 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07003015 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303016 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
3017 restricionModeProperty);
3018 if (ec)
3019 {
3020 phosphor::logging::log<phosphor::logging::level::ERR>(
3021 "ipmiSetSecurityMode: failed to get RestrictionMode property",
3022 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3023 return ipmi::responseUnspecifiedError();
3024 }
3025 auto currentRestrictionMode =
3026 securityNameSpace::RestrictionMode::convertModesFromString(
3027 std::get<std::string>(varRestrMode));
3028
3029 if (chInfo.mediumType !=
3030 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
3031 currentRestrictionMode > reqMode)
3032 {
3033 phosphor::logging::log<phosphor::logging::level::ERR>(
3034 "ipmiSetSecurityMode - Downgrading security mode not supported "
3035 "through system interface",
3036 phosphor::logging::entry(
3037 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
3038 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
3039 return ipmi::responseCommandNotAvailable();
3040 }
3041
3042 ec.clear();
3043 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07003044 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303045 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
3046 restricionModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003047 static_cast<ipmi::DbusVariant>(
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303048 securityNameSpace::convertForMessage(reqMode)));
3049
3050 if (ec)
3051 {
3052 phosphor::logging::log<phosphor::logging::level::ERR>(
3053 "ipmiSetSecurityMode: failed to set RestrictionMode property",
3054 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3055 return ipmi::responseUnspecifiedError();
3056 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303057
3058#ifdef BMC_VALIDATION_UNSECURE_FEATURE
3059 if (specialMode)
3060 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00003061 constexpr uint8_t mfgMode = 0x01;
3062 // Manufacturing mode is reserved. So can't enable this mode.
3063 if (specialMode.value() == mfgMode)
3064 {
3065 phosphor::logging::log<phosphor::logging::level::INFO>(
3066 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
3067 return ipmi::responseInvalidFieldRequest();
3068 }
3069
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303070 ec.clear();
3071 ctx->bus->yield_method_call<>(
3072 ctx->yield, ec, specialModeService, specialModeBasePath,
3073 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
3074 specialModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003075 static_cast<ipmi::DbusVariant>(securityNameSpace::convertForMessage(
3076 static_cast<securityNameSpace::SpecialMode::Modes>(
3077 specialMode.value()))));
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303078
3079 if (ec)
3080 {
3081 phosphor::logging::log<phosphor::logging::level::ERR>(
3082 "ipmiSetSecurityMode: failed to set SpecialMode property",
3083 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3084 return ipmi::responseUnspecifiedError();
3085 }
3086 }
3087#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303088 return ipmi::responseSuccess();
3089}
3090
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003091ipmi::RspType<uint8_t /* restore status */>
3092 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
3093{
3094 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
3095
3096 if (clr != expClr)
3097 {
3098 return ipmi::responseInvalidFieldRequest();
3099 }
3100 constexpr uint8_t cmdStatus = 0;
3101 constexpr uint8_t cmdDefaultRestore = 0xaa;
3102 constexpr uint8_t cmdFullRestore = 0xbb;
3103 constexpr uint8_t cmdFormat = 0xcc;
3104
3105 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3106
3107 switch (cmd)
3108 {
3109 case cmdStatus:
3110 break;
3111 case cmdDefaultRestore:
3112 case cmdFullRestore:
3113 case cmdFormat:
3114 {
3115 // write file to rwfs root
3116 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3117 std::ofstream restoreFile(restoreOpFname);
3118 if (!restoreFile)
3119 {
3120 return ipmi::responseUnspecifiedError();
3121 }
3122 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303123
3124 phosphor::logging::log<phosphor::logging::level::WARNING>(
3125 "Restore to default will be performed on next BMC boot",
3126 phosphor::logging::entry("ACTION=0x%0X", cmd));
3127
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003128 break;
3129 }
3130 default:
3131 return ipmi::responseInvalidFieldRequest();
3132 }
3133
3134 constexpr uint8_t restorePending = 0;
3135 constexpr uint8_t restoreComplete = 1;
3136
3137 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3138 ? restorePending
3139 : restoreComplete;
3140 return ipmi::responseSuccess(restoreStatus);
3141}
3142
Chen Yugang39736d52019-07-12 16:24:33 +08003143ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3144{
3145 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003146 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003147
3148 try
3149 {
3150 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3151 std::string service =
3152 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
3153 Value variant =
3154 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3155 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
3156
3157 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3158 std::get<std::string>(variant)))
3159 {
3160 case nmi::NMISource::BMCSourceSignal::None:
3161 bmcSource = static_cast<uint8_t>(NmiSource::none);
3162 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003163 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3164 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003165 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003166 case nmi::NMISource::BMCSourceSignal::Watchdog:
3167 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003168 break;
3169 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3170 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3171 break;
3172 case nmi::NMISource::BMCSourceSignal::MemoryError:
3173 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3174 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003175 case nmi::NMISource::BMCSourceSignal::PciBusError:
3176 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003177 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003178 case nmi::NMISource::BMCSourceSignal::PCH:
3179 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003180 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003181 case nmi::NMISource::BMCSourceSignal::Chipset:
3182 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003183 break;
3184 default:
3185 phosphor::logging::log<phosphor::logging::level::ERR>(
3186 "NMI source: invalid property!",
3187 phosphor::logging::entry(
3188 "PROP=%s", std::get<std::string>(variant).c_str()));
3189 return ipmi::responseResponseError();
3190 }
3191 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05003192 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003193 {
3194 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3195 return ipmi::responseResponseError();
3196 }
3197
3198 return ipmi::responseSuccess(bmcSource);
3199}
3200
3201ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3202{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003203 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003204
3205 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3206 nmi::NMISource::BMCSourceSignal::None;
3207
3208 switch (NmiSource(sourceId))
3209 {
3210 case NmiSource::none:
3211 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3212 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003213 case NmiSource::frontPanelButton:
3214 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003215 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003216 case NmiSource::watchdog:
3217 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003218 break;
3219 case NmiSource::chassisCmd:
3220 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3221 break;
3222 case NmiSource::memoryError:
3223 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3224 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003225 case NmiSource::pciBusError:
3226 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003227 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003228 case NmiSource::pch:
3229 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003230 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003231 case NmiSource::chipset:
3232 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003233 break;
3234 default:
3235 phosphor::logging::log<phosphor::logging::level::ERR>(
3236 "NMI source: invalid property!");
3237 return ipmi::responseResponseError();
3238 }
3239
3240 try
3241 {
3242 // keep NMI signal source
3243 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3244 std::string service =
3245 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003246 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3247 oemNmiBmcSourceObjPathProp,
3248 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003249 // set Enabled property to inform NMI source handling
3250 // to trigger a NMI_OUT BSOD.
3251 // if it's triggered by NMI source property changed,
3252 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3253 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3254 {
3255 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3256 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3257 static_cast<bool>(true));
3258 }
Chen Yugang39736d52019-07-12 16:24:33 +08003259 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003260 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003261 {
3262 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3263 return ipmi::responseResponseError();
3264 }
3265
3266 return ipmi::responseSuccess();
3267}
3268
James Feist63efafa2019-07-24 12:39:21 -07003269namespace dimmOffset
3270{
3271constexpr const char* dimmPower = "DimmPower";
3272constexpr const char* staticCltt = "StaticCltt";
3273constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3274constexpr const char* offsetInterface =
3275 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3276constexpr const char* property = "DimmOffset";
3277
3278}; // namespace dimmOffset
3279
3280ipmi::RspType<>
3281 ipmiOEMSetDimmOffset(uint8_t type,
3282 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3283{
3284 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3285 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3286 {
3287 return ipmi::responseInvalidFieldRequest();
3288 }
3289
3290 if (data.empty())
3291 {
3292 return ipmi::responseInvalidFieldRequest();
3293 }
3294 nlohmann::json json;
3295
3296 std::ifstream jsonStream(dimmOffsetFile);
3297 if (jsonStream.good())
3298 {
3299 json = nlohmann::json::parse(jsonStream, nullptr, false);
3300 if (json.is_discarded())
3301 {
3302 json = nlohmann::json();
3303 }
3304 jsonStream.close();
3305 }
3306
3307 std::string typeName;
3308 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3309 {
3310 typeName = dimmOffset::dimmPower;
3311 }
3312 else
3313 {
3314 typeName = dimmOffset::staticCltt;
3315 }
3316
3317 nlohmann::json& field = json[typeName];
3318
3319 for (const auto& [index, value] : data)
3320 {
3321 field[index] = value;
3322 }
3323
3324 for (nlohmann::json& val : field)
3325 {
3326 if (val == nullptr)
3327 {
3328 val = static_cast<uint8_t>(0);
3329 }
3330 }
3331
3332 std::ofstream output(dimmOffsetFile);
3333 if (!output.good())
3334 {
3335 std::cerr << "Error writing json file\n";
3336 return ipmi::responseResponseError();
3337 }
3338
3339 output << json.dump(4);
3340
3341 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3342 {
3343 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3344
Jason M. Bills0748c692022-09-08 15:34:08 -07003345 ipmi::DbusVariant offsets = field.get<std::vector<uint8_t>>();
James Feist63efafa2019-07-24 12:39:21 -07003346 auto call = bus->new_method_call(
3347 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3348 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3349 try
3350 {
3351 bus->call(call);
3352 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003353 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003354 {
3355 phosphor::logging::log<phosphor::logging::level::ERR>(
3356 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3357 phosphor::logging::entry("ERR=%s", e.what()));
3358 return ipmi::responseResponseError();
3359 }
3360 }
3361
3362 return ipmi::responseSuccess();
3363}
3364
3365ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3366{
3367
3368 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3369 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3370 {
3371 return ipmi::responseInvalidFieldRequest();
3372 }
3373
3374 std::ifstream jsonStream(dimmOffsetFile);
3375
3376 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3377 if (json.is_discarded())
3378 {
3379 std::cerr << "File error in " << dimmOffsetFile << "\n";
3380 return ipmi::responseResponseError();
3381 }
3382
3383 std::string typeName;
3384 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3385 {
3386 typeName = dimmOffset::dimmPower;
3387 }
3388 else
3389 {
3390 typeName = dimmOffset::staticCltt;
3391 }
3392
3393 auto it = json.find(typeName);
3394 if (it == json.end())
3395 {
3396 return ipmi::responseInvalidFieldRequest();
3397 }
3398
3399 if (it->size() <= index)
3400 {
3401 return ipmi::responseInvalidFieldRequest();
3402 }
3403
3404 uint8_t resp = it->at(index).get<uint8_t>();
3405 return ipmi::responseSuccess(resp);
3406}
3407
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003408namespace boot_options
3409{
3410
3411using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3412using IpmiValue = uint8_t;
3413constexpr auto ipmiDefault = 0;
3414
3415std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3416 {0x01, Source::Sources::Network},
3417 {0x02, Source::Sources::Disk},
3418 {0x05, Source::Sources::ExternalMedia},
3419 {0x0f, Source::Sources::RemovableMedia},
3420 {ipmiDefault, Source::Sources::Default}};
3421
3422std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003423 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003424
3425std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3426 {Source::Sources::Network, 0x01},
3427 {Source::Sources::Disk, 0x02},
3428 {Source::Sources::ExternalMedia, 0x05},
3429 {Source::Sources::RemovableMedia, 0x0f},
3430 {Source::Sources::Default, ipmiDefault}};
3431
3432std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003433 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003434
3435static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3436static constexpr auto bootSourceIntf =
3437 "xyz.openbmc_project.Control.Boot.Source";
3438static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3439static constexpr auto persistentObjPath =
3440 "/xyz/openbmc_project/control/host0/boot";
3441static constexpr auto oneTimePath =
3442 "/xyz/openbmc_project/control/host0/boot/one_time";
3443static constexpr auto bootSourceProp = "BootSource";
3444static constexpr auto bootModeProp = "BootMode";
3445static constexpr auto oneTimeBootEnableProp = "Enabled";
3446static constexpr auto httpBootMode =
3447 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3448
3449enum class BootOptionParameter : size_t
3450{
3451 setInProgress = 0x0,
3452 bootFlags = 0x5,
3453};
3454static constexpr uint8_t setComplete = 0x0;
3455static constexpr uint8_t setInProgress = 0x1;
3456static uint8_t transferStatus = setComplete;
3457static constexpr uint8_t setParmVersion = 0x01;
3458static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3459static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3460static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3461static constexpr uint8_t httpBoot = 0xd;
3462static constexpr uint8_t bootSourceMask = 0x3c;
3463
3464} // namespace boot_options
3465
3466ipmi::RspType<uint8_t, // version
3467 uint8_t, // param
3468 uint8_t, // data0, dependent on parameter
3469 std::optional<uint8_t> // data1, dependent on parameter
3470 >
3471 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3472{
3473 using namespace boot_options;
3474 uint8_t bootOption = 0;
3475
3476 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3477 {
3478 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3479 std::nullopt);
3480 }
3481
3482 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3483 {
3484 phosphor::logging::log<phosphor::logging::level::ERR>(
3485 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003486 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003487 }
3488
3489 try
3490 {
3491 auto oneTimeEnabled = false;
3492 // read one time Enabled property
3493 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3494 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3495 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3496 enabledIntf, oneTimeBootEnableProp);
3497 oneTimeEnabled = std::get<bool>(variant);
3498
3499 // get BootSource and BootMode properties
3500 // according to oneTimeEnable
3501 auto bootObjPath = oneTimePath;
3502 if (oneTimeEnabled == false)
3503 {
3504 bootObjPath = persistentObjPath;
3505 }
3506
3507 service = getService(*dbus, bootModeIntf, bootObjPath);
3508 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3509 bootModeProp);
3510
3511 auto bootMode =
3512 Mode::convertModesFromString(std::get<std::string>(variant));
3513
3514 service = getService(*dbus, bootSourceIntf, bootObjPath);
3515 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3516 bootSourceProp);
3517
3518 if (std::get<std::string>(variant) == httpBootMode)
3519 {
3520 bootOption = httpBoot;
3521 }
3522 else
3523 {
3524 auto bootSource = Source::convertSourcesFromString(
3525 std::get<std::string>(variant));
3526 bootOption = sourceDbusToIpmi.at(bootSource);
3527 if (Source::Sources::Default == bootSource)
3528 {
3529 bootOption = modeDbusToIpmi.at(bootMode);
3530 }
3531 }
3532
3533 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3534 : setParmBootFlagsValidPermanent;
3535 bootOption <<= 2; // shift for responseconstexpr
3536 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3537 bootOption);
3538 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003539 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003540 {
3541 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3542 return ipmi::responseResponseError();
3543 }
3544}
3545
3546ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3547 std::optional<uint8_t> bootOption)
3548{
3549 using namespace boot_options;
3550 auto oneTimeEnabled = false;
3551
Mike Jonesbc01d212022-06-16 12:41:33 -07003552 if (bootFlag == 0 && bootParam == 0)
3553 {
3554 phosphor::logging::log<phosphor::logging::level::ERR>(
3555 "Unsupported parameter");
3556 return ipmi::response(ccParameterNotSupported);
3557 }
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003558 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3559 {
3560 if (bootOption)
3561 {
3562 return ipmi::responseReqDataLenInvalid();
3563 }
3564
3565 if (transferStatus == setInProgress)
3566 {
3567 phosphor::logging::log<phosphor::logging::level::ERR>(
3568 "boot option set in progress!");
3569 return ipmi::responseResponseError();
3570 }
3571
3572 transferStatus = bootParam;
3573 return ipmi::responseSuccess();
3574 }
3575
3576 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3577 {
3578 phosphor::logging::log<phosphor::logging::level::ERR>(
3579 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003580 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003581 }
3582
3583 if (!bootOption)
3584 {
3585 return ipmi::responseReqDataLenInvalid();
3586 }
3587
3588 if (((bootOption.value() & bootSourceMask) >> 2) !=
3589 httpBoot) // not http boot, exit
3590 {
3591 phosphor::logging::log<phosphor::logging::level::ERR>(
3592 "wrong boot option parameter!");
3593 return ipmi::responseParmOutOfRange();
3594 }
3595
3596 try
3597 {
3598 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3599 setParmBootFlagsPermanent;
3600
3601 // read one time Enabled property
3602 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3603 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3604 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3605 enabledIntf, oneTimeBootEnableProp);
3606 oneTimeEnabled = std::get<bool>(variant);
3607
3608 /*
3609 * Check if the current boot setting is onetime or permanent, if the
3610 * request in the command is otherwise, then set the "Enabled"
3611 * property in one_time object path to 'True' to indicate onetime
3612 * and 'False' to indicate permanent.
3613 *
3614 * Once the onetime/permanent setting is applied, then the bootMode
3615 * and bootSource is updated for the corresponding object.
3616 */
3617 if (permanent == oneTimeEnabled)
3618 {
3619 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3620 oneTimeBootEnableProp, !permanent);
3621 }
3622
3623 // set BootSource and BootMode properties
3624 // according to oneTimeEnable or persistent
3625 auto bootObjPath = oneTimePath;
3626 if (oneTimeEnabled == false)
3627 {
3628 bootObjPath = persistentObjPath;
3629 }
3630 std::string bootMode =
3631 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3632 std::string bootSource = httpBootMode;
3633
3634 service = getService(*dbus, bootModeIntf, bootObjPath);
3635 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3636 bootMode);
3637
3638 service = getService(*dbus, bootSourceIntf, bootObjPath);
3639 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3640 bootSourceProp, bootSource);
3641 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003642 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003643 {
3644 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3645 return ipmi::responseResponseError();
3646 }
3647
3648 return ipmi::responseSuccess();
3649}
3650
Jason M. Bills0748c692022-09-08 15:34:08 -07003651using BasicVariantType = ipmi::DbusVariant;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003652using PropertyMapType =
3653 boost::container::flat_map<std::string, BasicVariantType>;
3654static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3655 "xyz.openbmc_project.Configuration.PSUPresence"};
3656int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3657 std::vector<uint64_t>& addrTable)
3658{
3659 boost::system::error_code ec;
3660 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3661 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3662 "/xyz/openbmc_project/object_mapper",
3663 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3664 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3665 if (ec)
3666 {
3667 phosphor::logging::log<phosphor::logging::level::ERR>(
3668 "Failed to set dbus property to cold redundancy");
3669 return -1;
3670 }
3671 for (const auto& object : subtree)
3672 {
3673 std::string pathName = object.first;
3674 for (const auto& serviceIface : object.second)
3675 {
3676 std::string serviceName = serviceIface.first;
3677
3678 ec.clear();
3679 PropertyMapType propMap =
3680 ctx->bus->yield_method_call<PropertyMapType>(
3681 ctx->yield, ec, serviceName, pathName,
3682 "org.freedesktop.DBus.Properties", "GetAll",
3683 "xyz.openbmc_project.Configuration.PSUPresence");
3684 if (ec)
3685 {
3686 phosphor::logging::log<phosphor::logging::level::ERR>(
3687 "Failed to set dbus property to cold redundancy");
3688 return -1;
3689 }
3690 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3691 auto psuAddress =
3692 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3693
3694 if (psuBus == nullptr || psuAddress == nullptr)
3695 {
3696 std::cerr << "error finding necessary "
3697 "entry in configuration\n";
3698 return -1;
3699 }
3700 bus = static_cast<uint8_t>(*psuBus);
3701 addrTable = *psuAddress;
3702 return 0;
3703 }
3704 }
3705 return -1;
3706}
3707
3708static const constexpr uint8_t addrOffset = 8;
3709static const constexpr uint8_t psuRevision = 0xd9;
3710static const constexpr uint8_t defaultPSUBus = 7;
3711// Second Minor, Primary Minor, Major
3712static const constexpr size_t verLen = 3;
3713ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3714{
3715 uint8_t bus = defaultPSUBus;
3716 std::vector<uint64_t> addrTable;
3717 std::vector<uint8_t> result;
3718 if (getPSUAddress(ctx, bus, addrTable))
3719 {
3720 std::cerr << "Failed to get PSU bus and address\n";
3721 return ipmi::responseResponseError();
3722 }
3723
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003724 for (const auto& targetAddr : addrTable)
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003725 {
3726 std::vector<uint8_t> writeData = {psuRevision};
3727 std::vector<uint8_t> readBuf(verLen);
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003728 uint8_t addr = static_cast<uint8_t>(targetAddr) + addrOffset;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003729 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3730
3731 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3732 if (retI2C != ipmi::ccSuccess)
3733 {
3734 for (size_t idx = 0; idx < verLen; idx++)
3735 {
3736 result.emplace_back(0x00);
3737 }
3738 }
3739 else
3740 {
3741 for (const uint8_t& data : readBuf)
3742 {
3743 result.emplace_back(data);
3744 }
3745 }
3746 }
3747
3748 return ipmi::responseSuccess(result);
3749}
3750
srikanta mondal2030d7c2020-05-03 17:25:25 +00003751std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3752 const std::string& name)
3753{
3754 Value dbusValue = 0;
3755 std::string serviceName;
3756
3757 boost::system::error_code ec =
3758 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3759
3760 if (ec)
3761 {
3762 phosphor::logging::log<phosphor::logging::level::ERR>(
3763 "Failed to perform Multinode getService.");
3764 return std::nullopt;
3765 }
3766
3767 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3768 multiNodeIntf, name, dbusValue);
3769 if (ec)
3770 {
3771 phosphor::logging::log<phosphor::logging::level::ERR>(
3772 "Failed to perform Multinode get property");
3773 return std::nullopt;
3774 }
3775
3776 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3777 if (!multiNodeVal)
3778 {
3779 phosphor::logging::log<phosphor::logging::level::ERR>(
3780 "getMultiNodeInfoPresence: error to get multinode");
3781 return std::nullopt;
3782 }
3783 return *multiNodeVal;
3784}
3785
3786/** @brief implements OEM get reading command
3787 * @param domain ID
3788 * @param reading Type
3789 * - 00h = platform Power Consumption
3790 * - 01h = inlet Air Temp
3791 * - 02h = icc_TDC from PECI
3792 * @param reserved, write as 0000h
3793 *
3794 * @returns IPMI completion code plus response data
3795 * - response
3796 * - domain ID
3797 * - reading Type
3798 * - 00h = platform Power Consumption
3799 * - 01h = inlet Air Temp
3800 * - 02h = icc_TDC from PECI
3801 * - reading
3802 */
3803ipmi::RspType<uint4_t, // domain ID
3804 uint4_t, // reading Type
3805 uint16_t // reading Value
3806 >
3807 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3808 uint4_t readingType, uint16_t reserved)
3809{
3810 constexpr uint8_t platformPower = 0;
3811 constexpr uint8_t inletAirTemp = 1;
3812 constexpr uint8_t iccTdc = 2;
3813
3814 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3815 {
3816 return ipmi::responseInvalidFieldRequest();
3817 }
3818
3819 // This command should run only from multi-node product.
3820 // For all other platforms this command will return invalid.
3821
3822 std::optional<uint8_t> nodeInfo =
3823 getMultiNodeInfoPresence(ctx, "NodePresence");
3824 if (!nodeInfo || !*nodeInfo)
3825 {
3826 return ipmi::responseInvalidCommand();
3827 }
3828
3829 uint16_t oemReadingValue = 0;
3830 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3831 {
3832 double value = 0;
3833 boost::system::error_code ec = ipmi::getDbusProperty(
3834 ctx, "xyz.openbmc_project.HwmonTempSensor",
3835 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3836 "xyz.openbmc_project.Sensor.Value", "Value", value);
3837 if (ec)
3838 {
3839 phosphor::logging::log<phosphor::logging::level::ERR>(
3840 "Failed to get BMC Get OEM temperature",
3841 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3842 return ipmi::responseUnspecifiedError();
3843 }
3844 // Take the Inlet temperature
3845 oemReadingValue = static_cast<uint16_t>(value);
3846 }
3847 else
3848 {
3849 phosphor::logging::log<phosphor::logging::level::ERR>(
3850 "Currently Get OEM Reading support only for Inlet Air Temp");
3851 return ipmi::responseParmOutOfRange();
3852 }
3853 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3854}
3855
AppaRao Puli28972062019-11-11 02:04:45 +05303856/** @brief implements the maximum size of
3857 * bridgeable messages used between KCS and
3858 * IPMB interfacesget security mode command.
3859 *
3860 * @returns IPMI completion code with following data
3861 * - KCS Buffer Size (In multiples of four bytes)
3862 * - IPMB Buffer Size (In multiples of four bytes)
3863 **/
3864ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3865{
3866 // for now this is hard coded; really this number is dependent on
3867 // the BMC kcs driver as well as the host kcs driver....
3868 // we can't know the latter.
3869 uint8_t kcsMaxBufferSize = 63 / 4;
3870 uint8_t ipmbMaxBufferSize = 128 / 4;
3871
3872 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3873}
3874
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003875ipmi::RspType<std::vector<uint8_t>>
3876 ipmiOEMReadPFRMailbox(ipmi::Context::ptr& ctx, const uint8_t readRegister,
3877 const uint8_t numOfBytes, uint8_t registerIdentifier)
3878{
3879 if (!ipmi::mailbox::i2cConfigLoaded)
3880 {
3881
3882 phosphor::logging::log<phosphor::logging::level::ERR>(
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003883 "Calling PFR Load Configuration Function to Get I2C Bus and Target "
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003884 "Address ");
3885
3886 ipmi::mailbox::loadPfrConfig(ctx, ipmi::mailbox::i2cConfigLoaded);
3887 }
3888
3889 if (!numOfBytes && !readRegister)
3890 {
3891 phosphor::logging::log<phosphor::logging::level::ERR>(
3892 "OEM IPMI command: Read & write count are 0 which is invalid ");
3893 return ipmi::responseInvalidFieldRequest();
3894 }
3895
3896 switch (registerIdentifier)
3897 {
3898 case ipmi::mailbox::registerType::fifoReadRegister:
3899 {
3900 // Check if readRegister is an FIFO read register
3901 if (registerIdentifier == 1)
3902 {
3903 if (ipmi::mailbox::readFifoReg.find(readRegister) ==
3904 ipmi::mailbox::readFifoReg.end())
3905 {
3906 phosphor::logging::log<phosphor::logging::level::ERR>(
3907 "OEM IPMI command: Register is not a Read FIFO ");
3908 return ipmi::responseInvalidFieldRequest();
3909 }
3910
3911 phosphor::logging::log<phosphor::logging::level::ERR>(
3912 "OEM IPMI command: Register is a Read FIFO ");
3913
3914 ipmi::mailbox::writefifo(ipmi::mailbox::provisioningCommand,
3915 readRegister);
3916 ipmi::mailbox::writefifo(ipmi::mailbox::triggerCommand,
3917 ipmi::mailbox::flushRead);
3918
3919 std::vector<uint8_t> writeData = {ipmi::mailbox::readFifo};
3920 std::vector<uint8_t> readBuf(1);
3921 std::vector<uint8_t> result;
3922
3923 for (int i = 0; i < numOfBytes; i++)
3924 {
3925
3926 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003927 ipmi::mailbox::targetAddr,
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003928 writeData, readBuf);
3929 if (ret != ipmi::ccSuccess)
3930 {
3931 return ipmi::response(ret);
3932 }
3933
3934 else
3935 {
3936 for (const uint8_t& data : readBuf)
3937 {
3938 result.emplace_back(data);
3939 }
3940 }
3941 }
3942
3943 return ipmi::responseSuccess(result);
3944 }
3945 }
3946
3947 case ipmi::mailbox::registerType::singleByteRegister:
3948 {
3949 phosphor::logging::log<phosphor::logging::level::ERR>(
3950 "OEM IPMI command: Register is a Single Byte Register ");
3951
3952 std::vector<uint8_t> writeData = {readRegister};
3953 std::vector<uint8_t> readBuf(numOfBytes);
3954
3955 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
Matt Simmering80d4d5f2023-02-15 15:18:51 -08003956 ipmi::mailbox::targetAddr,
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003957 writeData, readBuf);
3958 if (ret != ipmi::ccSuccess)
3959 {
3960 return ipmi::response(ret);
3961 }
3962 return ipmi::responseSuccess(readBuf);
3963 }
3964
3965 default:
3966 {
3967
3968 phosphor::logging::log<phosphor::logging::level::ERR>(
3969 "OEM IPMI command: Register identifier is not valid.It should "
3970 "be 0 "
3971 "for Single Byte Register and 1 for FIFO Read Register");
3972
3973 return ipmi::responseInvalidFieldRequest();
3974 }
3975 }
3976}
3977
Jason M. Bills64796042018-10-03 16:51:55 -07003978static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003979{
3980 phosphor::logging::log<phosphor::logging::level::INFO>(
3981 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003982 ipmiPrintAndRegister(intel::netFnGeneral,
3983 intel::general::cmdGetChassisIdentifier, NULL,
3984 ipmiOEMGetChassisIdentifier,
3985 PRIVILEGE_USER); // get chassis identifier
3986
3987 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3988 NULL, ipmiOEMSetSystemGUID,
3989 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003990
3991 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003992 registerHandler(prioOemBase, intel::netFnGeneral,
3993 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3994 ipmiOEMDisableBMCSystemReset);
3995
Jason M. Billsb02bf092019-08-15 13:01:56 -07003996 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003997 registerHandler(prioOemBase, intel::netFnGeneral,
3998 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3999 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07004000
Vernon Mauery98bbf692019-09-16 11:14:59 -07004001 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
4002 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004003
Chen Yugang7a04f3a2019-10-08 11:12:35 +08004004 registerHandler(prioOemBase, intel::netFnGeneral,
4005 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
4006 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004007
Vernon Mauery98bbf692019-09-16 11:14:59 -07004008 ipmiPrintAndRegister(intel::netFnGeneral,
4009 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
4010 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304011
Vernon Mauery98bbf692019-09-16 11:14:59 -07004012 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4013 intel::general::cmdSendEmbeddedFWUpdStatus,
4014 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304015
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05304016 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
4017 Privilege::Admin, ipmiOEMSlotIpmb);
4018
Vernon Mauery98bbf692019-09-16 11:14:59 -07004019 ipmiPrintAndRegister(intel::netFnGeneral,
4020 intel::general::cmdSetPowerRestoreDelay, NULL,
4021 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
4022
4023 ipmiPrintAndRegister(intel::netFnGeneral,
4024 intel::general::cmdGetPowerRestoreDelay, NULL,
4025 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
4026
4027 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4028 intel::general::cmdSetOEMUser2Activation,
4029 Privilege::Callback, ipmiOEMSetUser2Activation);
4030
4031 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4032 intel::general::cmdSetSpecialUserPassword,
4033 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05304034
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004035 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004036 registerHandler(prioOemBase, intel::netFnGeneral,
4037 intel::general::cmdGetProcessorErrConfig, Privilege::User,
4038 ipmiOEMGetProcessorErrConfig);
4039
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004040 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004041 registerHandler(prioOemBase, intel::netFnGeneral,
4042 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
4043 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004044
Vernon Mauery98bbf692019-09-16 11:14:59 -07004045 ipmiPrintAndRegister(intel::netFnGeneral,
4046 intel::general::cmdSetShutdownPolicy, NULL,
4047 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004048
Vernon Mauery98bbf692019-09-16 11:14:59 -07004049 ipmiPrintAndRegister(intel::netFnGeneral,
4050 intel::general::cmdGetShutdownPolicy, NULL,
4051 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004052
anil kumar appanaf945eee2019-09-25 23:29:11 +00004053 registerHandler(prioOemBase, intel::netFnGeneral,
4054 intel::general::cmdSetFanConfig, Privilege::User,
4055 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08004056
Vernon Mauery98bbf692019-09-16 11:14:59 -07004057 registerHandler(prioOemBase, intel::netFnGeneral,
4058 intel::general::cmdGetFanConfig, Privilege::User,
4059 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07004060
Vernon Mauery98bbf692019-09-16 11:14:59 -07004061 registerHandler(prioOemBase, intel::netFnGeneral,
4062 intel::general::cmdGetFanSpeedOffset, Privilege::User,
4063 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004064
Vernon Mauery98bbf692019-09-16 11:14:59 -07004065 registerHandler(prioOemBase, intel::netFnGeneral,
4066 intel::general::cmdSetFanSpeedOffset, Privilege::User,
4067 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004068
Vernon Mauery98bbf692019-09-16 11:14:59 -07004069 registerHandler(prioOemBase, intel::netFnGeneral,
4070 intel::general::cmdSetFscParameter, Privilege::User,
4071 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07004072
Vernon Mauery98bbf692019-09-16 11:14:59 -07004073 registerHandler(prioOemBase, intel::netFnGeneral,
4074 intel::general::cmdGetFscParameter, Privilege::User,
4075 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05304076
Vernon Mauery98bbf692019-09-16 11:14:59 -07004077 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4078 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
4079 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08004080
Vernon Mauery98bbf692019-09-16 11:14:59 -07004081 registerHandler(prioOemBase, intel::netFnGeneral,
4082 intel::general::cmdGetNmiStatus, Privilege::User,
4083 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08004084
Vernon Mauery98bbf692019-09-16 11:14:59 -07004085 registerHandler(prioOemBase, intel::netFnGeneral,
4086 intel::general::cmdSetNmiStatus, Privilege::Operator,
4087 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004088
Vernon Mauery98bbf692019-09-16 11:14:59 -07004089 registerHandler(prioOemBase, intel::netFnGeneral,
4090 intel::general::cmdGetEfiBootOptions, Privilege::User,
4091 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004092
Vernon Mauery98bbf692019-09-16 11:14:59 -07004093 registerHandler(prioOemBase, intel::netFnGeneral,
4094 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
4095 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304096
Vernon Mauery98bbf692019-09-16 11:14:59 -07004097 registerHandler(prioOemBase, intel::netFnGeneral,
4098 intel::general::cmdGetSecurityMode, Privilege::User,
4099 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304100
Vernon Mauery98bbf692019-09-16 11:14:59 -07004101 registerHandler(prioOemBase, intel::netFnGeneral,
4102 intel::general::cmdSetSecurityMode, Privilege::Admin,
4103 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004104
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00004105 registerHandler(prioOemBase, intel::netFnGeneral,
4106 intel::general::cmdGetLEDStatus, Privilege::Admin,
4107 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08004108
Vernon Mauery98bbf692019-09-16 11:14:59 -07004109 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
4110 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
4111 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
4112
4113 registerHandler(prioOemBase, intel::netFnGeneral,
4114 intel::general::cmdSetFaultIndication, Privilege::Operator,
4115 ipmiOEMSetFaultIndication);
4116
4117 registerHandler(prioOemBase, intel::netFnGeneral,
4118 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
4119 ipmiOEMSetCRConfig);
4120
4121 registerHandler(prioOemBase, intel::netFnGeneral,
4122 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
4123 ipmiOEMGetCRConfig);
4124
4125 registerHandler(prioOemBase, intel::netFnGeneral,
4126 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004127 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07004128
Vernon Mauery98bbf692019-09-16 11:14:59 -07004129 registerHandler(prioOemBase, intel::netFnGeneral,
4130 intel::general::cmdSetDimmOffset, Privilege::Operator,
4131 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07004132
Vernon Mauery98bbf692019-09-16 11:14:59 -07004133 registerHandler(prioOemBase, intel::netFnGeneral,
4134 intel::general::cmdGetDimmOffset, Privilege::Operator,
4135 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08004136
Cheng C Yang4e6ee152019-09-25 10:27:44 +08004137 registerHandler(prioOemBase, intel::netFnGeneral,
4138 intel::general::cmdGetPSUVersion, Privilege::User,
4139 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05304140
4141 registerHandler(prioOemBase, intel::netFnGeneral,
4142 intel::general::cmdGetBufferSize, Privilege::User,
4143 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00004144
4145 registerHandler(prioOemBase, intel::netFnGeneral,
4146 intel::general::cmdOEMGetReading, Privilege::User,
4147 ipmiOEMGetReading);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00004148
4149 registerHandler(prioOemBase, intel::netFnApp, intel::app::cmdPFRMailboxRead,
4150 Privilege::Admin, ipmiOEMReadPFRMailbox);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004151}
4152
4153} // namespace ipmi