blob: 1f8b99b99dedd1ece2c5b11c08f7eec8855b7c90 [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);
174static uint8_t slaveAddr = 56;
175static 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);
261 slaveAddr = static_cast<int>(*address);
262
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);
273 ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
274}
275
276} // namespace mailbox
277
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800278// Returns the Chassis Identifier (serial #)
279ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
280 ipmi_request_t request,
281 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700282 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800283 ipmi_context_t context)
284{
285 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700286 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800287 {
Jason M. Bills64796042018-10-03 16:51:55 -0700288 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800289 return IPMI_CC_REQ_DATA_LEN_INVALID;
290 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700291 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
292 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 {
Jason M. Bills64796042018-10-03 16:51:55 -0700294 *dataLen = serial.size(); // length will never exceed response length
295 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800296 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700297 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800298 return IPMI_CC_OK;
299 }
Jason M. Bills64796042018-10-03 16:51:55 -0700300 *dataLen = 0;
301 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800302}
303
304ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
305 ipmi_request_t request,
306 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700307 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800308{
309 static constexpr size_t safeBufferLength = 50;
310 char buf[safeBufferLength] = {0};
311 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
312
Jason M. Bills64796042018-10-03 16:51:55 -0700313 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800314 {
Jason M. Bills64796042018-10-03 16:51:55 -0700315 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800316 return IPMI_CC_REQ_DATA_LEN_INVALID;
317 }
318
Jason M. Bills64796042018-10-03 16:51:55 -0700319 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800320
321 snprintf(
322 buf, safeBufferLength,
323 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
324 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
325 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
326 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
327 Data->node3, Data->node2, Data->node1);
328 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
329 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800330
331 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
332 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700333 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
334 std::string service = getService(*dbus, intf, objpath);
335 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800336 return IPMI_CC_OK;
337}
338
Jason M. Billsb02bf092019-08-15 13:01:56 -0700339ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
340 uint7_t reserved1)
341{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000342 if (reserved1)
343 {
344 return ipmi::responseInvalidFieldRequest();
345 }
346
Jason M. Billsb02bf092019-08-15 13:01:56 -0700347 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
348
349 try
350 {
351 auto service =
352 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
353 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
354 bmcResetDisablesIntf, "ResetOnSMI",
355 !disableResetOnSMI);
356 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500357 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700358 {
359 phosphor::logging::log<phosphor::logging::level::ERR>(
360 "Failed to set BMC reset disables",
361 phosphor::logging::entry("EXCEPTION=%s", e.what()));
362 return ipmi::responseUnspecifiedError();
363 }
364
365 return ipmi::responseSuccess();
366}
367
368ipmi::RspType<bool, // disableResetOnSMI
369 uint7_t // reserved
370 >
371 ipmiOEMGetBMCResetDisables()
372{
373 bool disableResetOnSMI = true;
374
375 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
376 try
377 {
378 auto service =
379 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
380 Value variant =
381 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
382 bmcResetDisablesIntf, "ResetOnSMI");
383 disableResetOnSMI = !std::get<bool>(variant);
384 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500385 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700386 {
387 phosphor::logging::log<phosphor::logging::level::ERR>(
388 "Failed to get BMC reset disables",
389 phosphor::logging::entry("EXCEPTION=%s", e.what()));
390 return ipmi::responseUnspecifiedError();
391 }
392
393 return ipmi::responseSuccess(disableResetOnSMI, 0);
394}
395
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800396ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
397 ipmi_request_t request, ipmi_response_t response,
398 ipmi_data_len_t dataLen, ipmi_context_t context)
399{
400 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
401
Jason M. Bills64796042018-10-03 16:51:55 -0700402 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800403 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800404 *dataLen = 0;
405 return IPMI_CC_REQ_DATA_LEN_INVALID;
406 }
Jason M. Bills64796042018-10-03 16:51:55 -0700407 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000408 for (auto idChar : idString)
409 {
410 if (!std::isprint(static_cast<unsigned char>(idChar)))
411 {
412 phosphor::logging::log<phosphor::logging::level::ERR>(
413 "BIOS ID contains non printable character");
414 return IPMI_CC_INVALID_FIELD_REQUEST;
415 }
416 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800417
Vernon Mauery15419dd2019-05-24 09:40:30 -0700418 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000419 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
420 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800421 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800422 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
423 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700424 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800425 *dataLen = 1;
426 return IPMI_CC_OK;
427}
428
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000429bool getActiveHSCSoftwareVersionInfo(std::string& hscVersion, size_t hscNumber)
430{
431 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
432 try
433 {
434 std::string hsbpObjPath =
435 "/xyz/openbmc_project/software/HSBP_" + std::to_string(hscNumber);
436 auto service = getService(*dbus, biosVersionIntf, hsbpObjPath);
437 Value hscVersionValue =
438 getDbusProperty(*dbus, "xyz.openbmc_project.HsbpManager",
439 hsbpObjPath, biosVersionIntf, "Version");
440 hscVersion = std::get<std::string>(hscVersionValue);
441 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500442 catch (const sdbusplus::exception_t& e)
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000443 {
444 phosphor::logging::log<phosphor::logging::level::INFO>(
445 "Failed to retrieve HSBP version information",
446 phosphor::logging::entry("HSBP Number=%d", hscNumber));
447 return false;
448 }
449 return true;
450}
451
452bool getHscVerInfo(ipmi::Context::ptr ctx, uint8_t& hsc0Major,
453 uint8_t& hsc0Minor, uint8_t& hsc1Major, uint8_t& hsc1Minor,
454 uint8_t& hsc2Major, uint8_t& hsc2Minor)
455{
456 std::string hscVersion;
457 std::array<uint8_t, 6> hscVersions{0};
458
459 for (size_t hscNumber = 1; hscNumber <= 3; hscNumber++)
460 {
461 if (!getActiveHSCSoftwareVersionInfo(hscVersion, hscNumber))
462 {
463 continue;
464 }
465 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?)");
466 constexpr size_t matchedPhosphor = 4;
467 std::smatch results;
468 // hscVersion = BOOT_VER.FPGA_VER.SECURITY_REVISION (Example: 00.02.01)
469 if (std::regex_match(hscVersion, results, pattern1))
470 {
471 // Major version is FPGA_VER and Minor version is SECURITY_REV
472 if (results.size() == matchedPhosphor)
473 {
474 int index = (hscNumber - 1) * 2;
475 hscVersions[index] =
476 static_cast<uint8_t>(std::stoi(results[2]));
477 hscVersions[index + 1] =
478 static_cast<uint8_t>(std::stoi(results[3]));
479 }
480 }
481 }
482 hsc0Major = hscVersions[0];
483 hsc0Minor = hscVersions[1];
484 hsc1Major = hscVersions[2];
485 hsc1Minor = hscVersions[3];
486 hsc2Major = hscVersions[4];
487 hsc2Minor = hscVersions[5];
488 return true;
489}
490
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530491bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
492 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800493{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800494 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530495 std::string bmcVersion;
496 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800497 {
498 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800499 }
500
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530501 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800502 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800503 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800504 MetaRevision revision = rev.value();
505 bmcMajor = revision.major;
506
507 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
508 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
509 }
510
511 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530512 std::string meVersion;
513 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800514 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800515 return false;
516 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530517 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
518 constexpr size_t matchedPhosphor = 6;
519 std::smatch results;
520 if (std::regex_match(meVersion, results, pattern1))
521 {
522 if (results.size() == matchedPhosphor)
523 {
524 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
Jayaprakash Mutyalad0657022021-08-26 21:18:08 +0000525 meMinor = static_cast<uint8_t>(std::stoi(results[2]) << 4 |
526 std::stoi(results[3]));
AppaRao Puli32825a22020-01-17 15:52:41 +0530527 }
528 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800529 return true;
530}
531
532ipmi::RspType<
533 std::variant<std::string,
534 std::tuple<uint8_t, std::array<uint8_t, 2>,
535 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
536 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
537 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530538 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
539 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530540 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800541{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800542 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
543 {
544 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800545 }
546
547 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800548 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800549 {
550 case OEMDevEntityType::biosId:
551 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530552 // Byte 2&3, Only used with selecting BIOS
553 if (!countToRead || !offset)
554 {
555 return ipmi::responseReqDataLenInvalid();
556 }
557
Vernon Mauery15419dd2019-05-24 09:40:30 -0700558 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800559 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000560 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800561 try
562 {
Yong Li2742b852019-12-16 14:55:11 +0800563 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000564 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800565 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700566 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530567 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800568 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800569 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800570 }
Jason M. Bills64796042018-10-03 16:51:55 -0700571 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530572 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700573 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530574 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700575 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800576 else
577 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530578 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800579 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800580
581 std::string readBuf = {0};
582 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530583 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800584 (readBuf.begin()));
585 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800586 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500587 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800588 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800589 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800590 }
591 }
592 break;
593
594 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800595 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530596 // Byte 2&3, Only used with selecting BIOS
597 if (countToRead || offset)
598 {
599 return ipmi::responseReqDataLenInvalid();
600 }
601
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800602 constexpr const size_t verLen = 2;
603 constexpr const size_t verTotalLen = 10;
604 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
605 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
606 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
607 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
608 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
609 // data0/1: BMC version number; data6/7: ME version number
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530610 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800611 {
612 return ipmi::responseUnspecifiedError();
613 }
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000614 if (!getHscVerInfo(ctx, hsc0Buf[0], hsc0Buf[1], hsc1Buf[0],
615 hsc1Buf[1], hsc2Buf[0], hsc2Buf[1]))
616 {
617 return ipmi::responseUnspecifiedError();
618 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800619 return ipmi::responseSuccess(
620 std::tuple<
621 uint8_t, std::array<uint8_t, verLen>,
622 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
623 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
624 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
625 }
626 break;
627
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800628 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800629 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530630 // Byte 2&3, Only used with selecting BIOS
631 if (countToRead || offset)
632 {
633 return ipmi::responseReqDataLenInvalid();
634 }
635
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800636 constexpr const size_t sdrLen = 2;
637 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
638 return ipmi::responseSuccess(
639 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
640 readBuf});
641 }
642 break;
643
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800644 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800645 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800646 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800647}
648
649ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
650 ipmi_request_t request, ipmi_response_t response,
651 ipmi_data_len_t dataLen, ipmi_context_t context)
652{
653 if (*dataLen != 0)
654 {
Jason M. Bills64796042018-10-03 16:51:55 -0700655 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800656 return IPMI_CC_REQ_DATA_LEN_INVALID;
657 }
658
659 *dataLen = 1;
660 uint8_t* res = reinterpret_cast<uint8_t*>(response);
661 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
662 // AIC is available so that BIOS will not timeout repeatly which leads to
663 // slow booting.
664 *res = 0; // Byte1=Count of SlotPosition/FruID records.
665 return IPMI_CC_OK;
666}
667
Jason M. Bills64796042018-10-03 16:51:55 -0700668ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
669 ipmi_request_t request,
670 ipmi_response_t response,
671 ipmi_data_len_t dataLen,
672 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800673{
Jason M. Bills64796042018-10-03 16:51:55 -0700674 GetPowerRestoreDelayRes* resp =
675 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
676
677 if (*dataLen != 0)
678 {
679 *dataLen = 0;
680 return IPMI_CC_REQ_DATA_LEN_INVALID;
681 }
682
Vernon Mauery15419dd2019-05-24 09:40:30 -0700683 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700684 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700685 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700686 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700687 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700688 powerRestoreDelayIntf, powerRestoreDelayProp);
689
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300690 uint64_t val = std::get<uint64_t>(variant);
691 val /= 1000000UL;
692 uint16_t delay = val;
Jason M. Bills64796042018-10-03 16:51:55 -0700693 resp->byteLSB = delay;
694 resp->byteMSB = delay >> 8;
695
696 *dataLen = sizeof(GetPowerRestoreDelayRes);
697
698 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800699}
700
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800701static uint8_t bcdToDec(uint8_t val)
702{
703 return ((val / 16 * 10) + (val % 16));
704}
705
706// Allows an update utility or system BIOS to send the status of an embedded
707// firmware update attempt to the BMC. After received, BMC will create a logging
708// record.
709ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
710 uint8_t majorRevision,
711 uint8_t minorRevision,
712 uint32_t auxInfo)
713{
714 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700715 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800716 target = (target & selEvtTargetMask) >> selEvtTargetShift;
717
718 /* make sure the status is 0, 1, or 2 as per the spec */
719 if (status > 2)
720 {
721 return ipmi::response(ipmi::ccInvalidFieldRequest);
722 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700723 /* make sure the target is 0, 1, 2, or 4 as per the spec */
724 if (target > 4 || target == 3)
725 {
726 return ipmi::response(ipmi::ccInvalidFieldRequest);
727 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800728 /*orignal OEM command is to record OEM SEL.
729 But openbmc does not support OEM SEL, so we redirect it to redfish event
730 logging. */
731 std::string buildInfo;
732 std::string action;
733 switch (FWUpdateTarget(target))
734 {
735 case FWUpdateTarget::targetBMC:
736 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700737 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800738 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
739 " BuildID: " + std::to_string(auxInfo);
740 buildInfo += std::to_string(auxInfo);
741 break;
742 case FWUpdateTarget::targetBIOS:
743 firmware = "BIOS";
744 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700745 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800746 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
747 " minor: " +
748 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
749 " ReleaseNumber: " + // ASCII encoded
750 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
751 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
752 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
753 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
754 break;
755 case FWUpdateTarget::targetME:
756 firmware = "ME";
757 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700758 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800759 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
760 " minor2: " +
761 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
762 " build1: " +
763 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
764 " build2: " +
765 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
766 break;
767 case FWUpdateTarget::targetOEMEWS:
768 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700769 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800770 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
771 " BuildID: " + std::to_string(auxInfo);
772 break;
773 }
774
Jason M. Billsdc249272019-04-03 09:58:40 -0700775 static const std::string openBMCMessageRegistryVersion("0.1");
776 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
777
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800778 switch (status)
779 {
780 case 0x0:
781 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700782 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800783 break;
784 case 0x1:
785 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700786 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800787 break;
788 case 0x2:
789 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700790 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800791 break;
792 default:
793 action = "unknown";
794 break;
795 }
796
Jason M. Billsdc249272019-04-03 09:58:40 -0700797 std::string firmwareInstanceStr =
798 firmware + " instance: " + std::to_string(instance);
799 std::string message("[firmware update] " + firmwareInstanceStr +
800 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800801
802 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700803 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
804 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
805 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800806 return ipmi::responseSuccess();
807}
808
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530809ipmi::RspType<uint8_t, std::vector<uint8_t>>
810 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
811 uint2_t slotNumber, uint3_t baseBoardSlotNum,
812 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
813 uint8_t netFn, uint8_t cmd,
814 std::optional<std::vector<uint8_t>> writeData)
815{
816 if (reserved1 || reserved2)
817 {
818 return ipmi::responseInvalidFieldRequest();
819 }
820
821 boost::system::error_code ec;
822 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
823 std::vector<uint8_t>>;
824 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
825 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
826 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
827 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
828 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
829 *writeData);
830 if (ec)
831 {
832 phosphor::logging::log<phosphor::logging::level::ERR>(
833 "Failed to call dbus method SlotIpmbRequest");
834 return ipmi::responseUnspecifiedError();
835 }
836
837 std::vector<uint8_t> dataReceived(0);
838 int status = -1;
839 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
840
841 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
842
843 if (status)
844 {
845 phosphor::logging::log<phosphor::logging::level::ERR>(
846 "Failed to get response from SlotIpmbRequest");
847 return ipmi::responseResponseError();
848 }
849 return ipmi::responseSuccess(cc, dataReceived);
850}
851
Jason M. Bills64796042018-10-03 16:51:55 -0700852ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
853 ipmi_request_t request,
854 ipmi_response_t response,
855 ipmi_data_len_t dataLen,
856 ipmi_context_t context)
857{
858 SetPowerRestoreDelayReq* data =
859 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
860 uint16_t delay = 0;
861
862 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
863 {
864 *dataLen = 0;
865 return IPMI_CC_REQ_DATA_LEN_INVALID;
866 }
867 delay = data->byteMSB;
868 delay = (delay << 8) | data->byteLSB;
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300869 uint64_t val = delay * 1000000;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700870 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700871 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700872 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
873 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Andrei Kartashevc42c7ed2022-01-10 12:17:34 +0300874 powerRestoreDelayIntf, powerRestoreDelayProp, val);
Jason M. Bills64796042018-10-03 16:51:55 -0700875 *dataLen = 0;
876
877 return IPMI_CC_OK;
878}
879
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700880static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700881{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700882 static constexpr const char* cpuPresencePathPrefix =
883 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
884 static constexpr const char* cpuPresenceIntf =
885 "xyz.openbmc_project.Inventory.Item";
886 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
887 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
888 try
Jason M. Bills64796042018-10-03 16:51:55 -0700889 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700890 auto service =
891 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
892
893 ipmi::Value result = ipmi::getDbusProperty(
894 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
895 return std::get<bool>(result);
896 }
897 catch (const std::exception& e)
898 {
899 phosphor::logging::log<phosphor::logging::level::INFO>(
900 "Cannot find processor presence",
901 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
902 return false;
903 }
904}
905
906ipmi::RspType<bool, // CATERR Reset Enabled
907 bool, // ERR2 Reset Enabled
908 uint6_t, // reserved
909 uint8_t, // reserved, returns 0x3F
910 uint6_t, // CPU1 CATERR Count
911 uint2_t, // CPU1 Status
912 uint6_t, // CPU2 CATERR Count
913 uint2_t, // CPU2 Status
914 uint6_t, // CPU3 CATERR Count
915 uint2_t, // CPU3 Status
916 uint6_t, // CPU4 CATERR Count
917 uint2_t, // CPU4 Status
918 uint8_t // Crashdump Count
919 >
920 ipmiOEMGetProcessorErrConfig()
921{
922 bool resetOnCATERR = false;
923 bool resetOnERR2 = false;
924 uint6_t cpu1CATERRCount = 0;
925 uint6_t cpu2CATERRCount = 0;
926 uint6_t cpu3CATERRCount = 0;
927 uint6_t cpu4CATERRCount = 0;
928 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700929 uint2_t cpu1Status = cpuPresent("CPU_1")
930 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
931 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
932 uint2_t cpu2Status = cpuPresent("CPU_2")
933 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
934 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
935 uint2_t cpu3Status = cpuPresent("CPU_3")
936 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
937 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
938 uint2_t cpu4Status = cpuPresent("CPU_4")
939 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
940 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700941
942 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
943 try
944 {
945 auto service = ipmi::getService(*busp, processorErrConfigIntf,
946 processorErrConfigObjPath);
947
948 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
949 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
950 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
951 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
952 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
953 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
954 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
955 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
956 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
957 }
958 catch (const std::exception& e)
959 {
960 phosphor::logging::log<phosphor::logging::level::ERR>(
961 "Failed to fetch processor error config",
962 phosphor::logging::entry("ERROR=%s", e.what()));
963 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700964 }
965
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700966 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
967 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
968 cpu2Status, cpu3CATERRCount, cpu3Status,
969 cpu4CATERRCount, cpu4Status, crashdumpCount);
970}
Jason M. Bills64796042018-10-03 16:51:55 -0700971
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700972ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
973 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
974 std::optional<bool> clearCPUErrorCount,
975 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
976{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000977 if (reserved1 || reserved2)
978 {
979 return ipmi::responseInvalidFieldRequest();
980 }
981
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700982 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700983
984 try
985 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000986 if (reserved3.value_or(0))
987 {
988 return ipmi::responseInvalidFieldRequest();
989 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700990 auto service = ipmi::getService(*busp, processorErrConfigIntf,
991 processorErrConfigObjPath);
992 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
993 processorErrConfigIntf, "ResetOnCATERR",
994 resetOnCATERR);
995 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
996 processorErrConfigIntf, "ResetOnERR2",
997 resetOnERR2);
998 if (clearCPUErrorCount.value_or(false))
999 {
1000 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001001 processorErrConfigIntf, "ErrorCountCPU1",
1002 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001003 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001004 processorErrConfigIntf, "ErrorCountCPU2",
1005 static_cast<uint8_t>(0));
1006 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1007 processorErrConfigIntf, "ErrorCountCPU3",
1008 static_cast<uint8_t>(0));
1009 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1010 processorErrConfigIntf, "ErrorCountCPU4",
1011 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001012 }
1013 if (clearCrashdumpCount.value_or(false))
1014 {
1015 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001016 processorErrConfigIntf, "CrashdumpCount",
1017 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001018 }
Jason M. Bills64796042018-10-03 16:51:55 -07001019 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001020 catch (const std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -07001021 {
Kuiying Wangbc546672018-11-23 15:41:05 +08001022 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001023 "Failed to set processor error config",
1024 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1025 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -07001026 }
1027
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001028 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -07001029}
1030
Yong Li703922d2018-11-06 13:25:31 +08001031ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1032 ipmi_request_t request,
1033 ipmi_response_t response,
1034 ipmi_data_len_t dataLen,
1035 ipmi_context_t context)
1036{
1037 GetOEMShutdownPolicyRes* resp =
1038 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
1039
1040 if (*dataLen != 0)
1041 {
1042 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +08001043 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +08001044 *dataLen = 0;
1045 return IPMI_CC_REQ_DATA_LEN_INVALID;
1046 }
1047
1048 *dataLen = 0;
1049
1050 try
1051 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001052 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +08001053 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001054 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
1055 Value variant = getDbusProperty(
1056 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
1057 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +08001058
1059 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1060 convertPolicyFromString(std::get<std::string>(variant)) ==
1061 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1062 NoShutdownOnOCOT)
1063 {
1064 resp->policy = 0;
1065 }
1066 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1067 convertPolicyFromString(std::get<std::string>(variant)) ==
1068 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1069 Policy::ShutdownOnOCOT)
1070 {
1071 resp->policy = 1;
1072 }
1073 else
1074 {
1075 phosphor::logging::log<phosphor::logging::level::ERR>(
1076 "oem_set_shutdown_policy: invalid property!",
1077 phosphor::logging::entry(
1078 "PROP=%s", std::get<std::string>(variant).c_str()));
1079 return IPMI_CC_UNSPECIFIED_ERROR;
1080 }
Yong Li703922d2018-11-06 13:25:31 +08001081 // TODO needs to check if it is multi-node products,
1082 // policy is only supported on node 3/4
1083 resp->policySupport = shutdownPolicySupported;
1084 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001085 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001086 {
1087 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1088 return IPMI_CC_UNSPECIFIED_ERROR;
1089 }
1090
1091 *dataLen = sizeof(GetOEMShutdownPolicyRes);
1092 return IPMI_CC_OK;
1093}
1094
1095ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1096 ipmi_request_t request,
1097 ipmi_response_t response,
1098 ipmi_data_len_t dataLen,
1099 ipmi_context_t context)
1100{
1101 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +08001102 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
1103 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1104 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +08001105
1106 // TODO needs to check if it is multi-node products,
1107 // policy is only supported on node 3/4
1108 if (*dataLen != 1)
1109 {
1110 phosphor::logging::log<phosphor::logging::level::ERR>(
1111 "oem_set_shutdown_policy: invalid input len!");
1112 *dataLen = 0;
1113 return IPMI_CC_REQ_DATA_LEN_INVALID;
1114 }
1115
1116 *dataLen = 0;
1117 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
1118 {
1119 phosphor::logging::log<phosphor::logging::level::ERR>(
1120 "oem_set_shutdown_policy: invalid input!");
1121 return IPMI_CC_INVALID_FIELD_REQUEST;
1122 }
1123
Yong Li0669d192019-05-06 14:01:46 +08001124 if (*req == noShutdownOnOCOT)
1125 {
1126 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1127 Policy::NoShutdownOnOCOT;
1128 }
1129 else
1130 {
1131 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1132 Policy::ShutdownOnOCOT;
1133 }
1134
Yong Li703922d2018-11-06 13:25:31 +08001135 try
1136 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001137 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +08001138 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001139 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +08001140 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001141 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +08001142 oemShutdownPolicyObjPathProp,
1143 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +08001144 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001145 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001146 {
1147 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1148 return IPMI_CC_UNSPECIFIED_ERROR;
1149 }
1150
1151 return IPMI_CC_OK;
1152}
1153
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301154/** @brief implementation for check the DHCP or not in IPv4
1155 * @param[in] Channel - Channel number
1156 * @returns true or false.
1157 */
1158static bool isDHCPEnabled(uint8_t Channel)
1159{
1160 try
1161 {
1162 auto ethdevice = getChannelName(Channel);
1163 if (ethdevice.empty())
1164 {
1165 return false;
1166 }
1167 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001168 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301169 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001170 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1171 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301172 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001173 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301174 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1175 {
1176 return true;
1177 }
1178 else
1179 {
1180 return false;
1181 }
1182 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001183 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301184 {
1185 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1186 return true;
1187 }
1188}
1189
1190/** @brief implementes for check the DHCP or not in IPv6
1191 * @param[in] Channel - Channel number
1192 * @returns true or false.
1193 */
1194static bool isDHCPIPv6Enabled(uint8_t Channel)
1195{
1196
1197 try
1198 {
1199 auto ethdevice = getChannelName(Channel);
1200 if (ethdevice.empty())
1201 {
1202 return false;
1203 }
1204 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001205 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301206 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001207 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1208 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301209 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001210 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301211 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1212 {
1213 return true;
1214 }
1215 else
1216 {
1217 return false;
1218 }
1219 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001220 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301221 {
1222 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1223 return true;
1224 }
1225}
1226
1227/** @brief implementes the creating of default new user
1228 * @param[in] userName - new username in 16 bytes.
1229 * @param[in] userPassword - new password in 20 bytes
1230 * @returns ipmi completion code.
1231 */
1232ipmi::RspType<> ipmiOEMSetUser2Activation(
1233 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001234 const SecureBuffer& userPassword)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301235{
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001236 if (userPassword.size() != ipmi::maxIpmi20PasswordSize)
1237 {
1238 return ipmi::responseReqDataLenInvalid();
1239 }
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301240 bool userState = false;
1241 // Check for System Interface not exist and LAN should be static
1242 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1243 {
Manish Baing440f62b2021-07-15 22:00:37 +00001244 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301245 try
1246 {
1247 getChannelInfo(channel, chInfo);
1248 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001249 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301250 {
1251 phosphor::logging::log<phosphor::logging::level::ERR>(
1252 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1253 phosphor::logging::entry("MSG: %s", e.description()));
1254 return ipmi::response(ipmi::ccUnspecifiedError);
1255 }
1256 if (chInfo.mediumType ==
1257 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1258 {
1259 phosphor::logging::log<phosphor::logging::level::ERR>(
1260 "ipmiOEMSetUser2Activation: system interface exist .");
1261 return ipmi::response(ipmi::ccCommandNotAvailable);
1262 }
1263 else
1264 {
1265
1266 if (chInfo.mediumType ==
1267 static_cast<uint8_t>(EChannelMediumType::lan8032))
1268 {
1269 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1270 {
1271 phosphor::logging::log<phosphor::logging::level::ERR>(
1272 "ipmiOEMSetUser2Activation: DHCP enabled .");
1273 return ipmi::response(ipmi::ccCommandNotAvailable);
1274 }
1275 }
1276 }
1277 }
1278 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1279 if (ipmi::ccSuccess ==
1280 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1281 {
1282 if (enabledUsers > 1)
1283 {
1284 phosphor::logging::log<phosphor::logging::level::ERR>(
1285 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1286 return ipmi::response(ipmi::ccCommandNotAvailable);
1287 }
1288 // Check the user 2 is enabled or not
1289 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1290 if (userState == true)
1291 {
1292 phosphor::logging::log<phosphor::logging::level::ERR>(
1293 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1294 return ipmi::response(ipmi::ccCommandNotAvailable);
1295 }
1296 }
1297 else
1298 {
1299 return ipmi::response(ipmi::ccUnspecifiedError);
1300 }
1301
1302#if BYTE_ORDER == LITTLE_ENDIAN
1303 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1304#endif
1305#if BYTE_ORDER == BIG_ENDIAN
1306 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1307#endif
1308
Vernon Mauery037cabd2020-05-14 12:16:01 -07001309 // ipmiUserSetUserName correctly handles char*, possibly non-null
1310 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001311 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1312 sizeof(userName));
1313 const std::string userNameRaw(
1314 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001315
Vernon Mauery037cabd2020-05-14 12:16:01 -07001316 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301317 {
1318 if (ipmi::ccSuccess ==
1319 ipmiUserSetUserPassword(
1320 ipmiDefaultUserId,
1321 reinterpret_cast<const char*>(userPassword.data())))
1322 {
1323 if (ipmi::ccSuccess ==
1324 ipmiUserSetPrivilegeAccess(
1325 ipmiDefaultUserId,
1326 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1327 privAccess, true))
1328 {
1329 phosphor::logging::log<phosphor::logging::level::INFO>(
1330 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001331
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301332 return ipmi::responseSuccess();
1333 }
1334 }
1335 // we need to delete the default user id which added in this command as
1336 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001337 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301338 phosphor::logging::log<phosphor::logging::level::ERR>(
1339 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1340 }
1341 else
1342 {
1343 phosphor::logging::log<phosphor::logging::level::ERR>(
1344 "ipmiOEMSetUser2Activation: Setting username failed.");
1345 }
1346
1347 return ipmi::response(ipmi::ccCommandNotAvailable);
1348}
1349
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301350/** @brief implementes executing the linux command
1351 * @param[in] linux command
1352 * @returns status
1353 */
1354
1355static uint8_t executeCmd(const char* path)
1356{
1357 boost::process::child execProg(path);
1358 execProg.wait();
1359
1360 int retCode = execProg.exit_code();
1361 if (retCode)
1362 {
1363 return ipmi::ccUnspecifiedError;
1364 }
1365 return ipmi::ccSuccess;
1366}
1367
1368/** @brief implementes ASD Security event logging
1369 * @param[in] Event message string
1370 * @param[in] Event Severity
1371 * @returns status
1372 */
1373
1374static void atScaleDebugEventlog(std::string msg, int severity)
1375{
1376 std::string eventStr = "OpenBMC.0.1." + msg;
1377 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1378 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1379 eventStr.c_str(), NULL);
1380}
1381
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301382/** @brief implementes setting password for special user
1383 * @param[in] specialUserIndex
1384 * @param[in] userPassword - new password in 20 bytes
1385 * @returns ipmi completion code.
1386 */
1387ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1388 uint8_t specialUserIndex,
1389 std::vector<uint8_t> userPassword)
1390{
1391 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301392 ipmi_ret_t status = ipmi::ccSuccess;
1393
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301394 try
1395 {
1396 getChannelInfo(ctx->channel, chInfo);
1397 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001398 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301399 {
1400 phosphor::logging::log<phosphor::logging::level::ERR>(
1401 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1402 phosphor::logging::entry("MSG: %s", e.description()));
1403 return ipmi::responseUnspecifiedError();
1404 }
1405 if (chInfo.mediumType !=
1406 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1407 {
1408 phosphor::logging::log<phosphor::logging::level::ERR>(
1409 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1410 "interface");
1411 return ipmi::responseCommandNotAvailable();
1412 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301413
1414 // 0 for root user and 1 for AtScaleDebug is allowed
1415 if (specialUserIndex >
1416 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301417 {
1418 phosphor::logging::log<phosphor::logging::level::ERR>(
1419 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1420 return ipmi::responseParmOutOfRange();
1421 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301422 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301423 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301424 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001425 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301426 if (userPassword.size() < minPasswordSizeRequired ||
1427 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1428 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001429 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301430 return ipmi::responseReqDataLenInvalid();
1431 }
1432 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1433 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001434 // Clear sensitive data
1435 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301436 if (specialUserIndex ==
1437 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1438 {
1439 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1440
1441 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1442 }
1443 else
1444 {
1445 status = ipmiSetSpecialUserPassword("root", passwd);
1446 }
1447 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301448 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301449 else
1450 {
1451 if (specialUserIndex ==
1452 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1453 {
1454 status = executeCmd("passwd -d root");
1455 }
1456 else
1457 {
1458
1459 status = executeCmd("passwd -d asdbg");
1460
1461 if (status == 0)
1462 {
1463 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1464 LOG_INFO);
1465 }
1466 }
1467 return ipmi::response(status);
1468 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301469}
1470
Kuiying Wang45f04982018-12-26 09:23:08 +08001471namespace ledAction
1472{
1473using namespace sdbusplus::xyz::openbmc_project::Led::server;
1474std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001475 {Physical::Action::Off, 0},
1476 {Physical::Action::On, 2},
1477 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001478
1479std::map<uint8_t, std::string> offsetObjPath = {
1480 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1481
1482} // namespace ledAction
1483
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001484int8_t getLEDState(sdbusplus::bus_t& bus, const std::string& intf,
Kuiying Wang45f04982018-12-26 09:23:08 +08001485 const std::string& objPath, uint8_t& state)
1486{
1487 try
1488 {
1489 std::string service = getService(bus, intf, objPath);
1490 Value stateValue =
1491 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001492 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001493 state = ledAction::actionDbusToIpmi.at(
1494 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1495 convertActionFromString(strState));
1496 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001497 catch (const sdbusplus::exception_t& e)
Kuiying Wang45f04982018-12-26 09:23:08 +08001498 {
1499 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1500 return -1;
1501 }
1502 return 0;
1503}
1504
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001505ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001506{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001507 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001508 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001509 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001510 for (auto it = ledAction::offsetObjPath.begin();
1511 it != ledAction::offsetObjPath.end(); ++it)
1512 {
1513 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001514 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001515 {
1516 phosphor::logging::log<phosphor::logging::level::ERR>(
1517 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001518 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001519 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001520 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001521 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001522 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001523}
1524
Yong Li23737fe2019-02-19 08:49:55 +08001525ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1526 ipmi_request_t request,
1527 ipmi_response_t response,
1528 ipmi_data_len_t dataLen,
1529 ipmi_context_t context)
1530{
1531 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1532 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1533
1534 if (*dataLen == 0)
1535 {
1536 phosphor::logging::log<phosphor::logging::level::ERR>(
1537 "CfgHostSerial: invalid input len!",
1538 phosphor::logging::entry("LEN=%d", *dataLen));
1539 return IPMI_CC_REQ_DATA_LEN_INVALID;
1540 }
1541
1542 switch (req->command)
1543 {
1544 case getHostSerialCfgCmd:
1545 {
1546 if (*dataLen != 1)
1547 {
1548 phosphor::logging::log<phosphor::logging::level::ERR>(
1549 "CfgHostSerial: invalid input len!");
1550 *dataLen = 0;
1551 return IPMI_CC_REQ_DATA_LEN_INVALID;
1552 }
1553
1554 *dataLen = 0;
1555
1556 boost::process::ipstream is;
1557 std::vector<std::string> data;
1558 std::string line;
1559 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1560 boost::process::std_out > is);
1561
1562 while (c1.running() && std::getline(is, line) && !line.empty())
1563 {
1564 data.push_back(line);
1565 }
1566
1567 c1.wait();
1568 if (c1.exit_code())
1569 {
1570 phosphor::logging::log<phosphor::logging::level::ERR>(
1571 "CfgHostSerial:: error on execute",
1572 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1573 // Using the default value
1574 *resp = 0;
1575 }
1576 else
1577 {
1578 if (data.size() != 1)
1579 {
1580 phosphor::logging::log<phosphor::logging::level::ERR>(
1581 "CfgHostSerial:: error on read env");
1582 return IPMI_CC_UNSPECIFIED_ERROR;
1583 }
1584 try
1585 {
1586 unsigned long tmp = std::stoul(data[0]);
1587 if (tmp > std::numeric_limits<uint8_t>::max())
1588 {
1589 throw std::out_of_range("Out of range");
1590 }
1591 *resp = static_cast<uint8_t>(tmp);
1592 }
1593 catch (const std::invalid_argument& e)
1594 {
1595 phosphor::logging::log<phosphor::logging::level::ERR>(
1596 "invalid config ",
1597 phosphor::logging::entry("ERR=%s", e.what()));
1598 return IPMI_CC_UNSPECIFIED_ERROR;
1599 }
1600 catch (const std::out_of_range& e)
1601 {
1602 phosphor::logging::log<phosphor::logging::level::ERR>(
1603 "out_of_range config ",
1604 phosphor::logging::entry("ERR=%s", e.what()));
1605 return IPMI_CC_UNSPECIFIED_ERROR;
1606 }
1607 }
1608
1609 *dataLen = 1;
1610 break;
1611 }
1612 case setHostSerialCfgCmd:
1613 {
1614 if (*dataLen != sizeof(CfgHostSerialReq))
1615 {
1616 phosphor::logging::log<phosphor::logging::level::ERR>(
1617 "CfgHostSerial: invalid input len!");
1618 *dataLen = 0;
1619 return IPMI_CC_REQ_DATA_LEN_INVALID;
1620 }
1621
1622 *dataLen = 0;
1623
1624 if (req->parameter > HostSerialCfgParamMax)
1625 {
1626 phosphor::logging::log<phosphor::logging::level::ERR>(
1627 "CfgHostSerial: invalid input!");
1628 return IPMI_CC_INVALID_FIELD_REQUEST;
1629 }
1630
1631 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1632 std::to_string(req->parameter));
1633
1634 c1.wait();
1635 if (c1.exit_code())
1636 {
1637 phosphor::logging::log<phosphor::logging::level::ERR>(
1638 "CfgHostSerial:: error on execute",
1639 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1640 return IPMI_CC_UNSPECIFIED_ERROR;
1641 }
1642 break;
1643 }
1644 default:
1645 phosphor::logging::log<phosphor::logging::level::ERR>(
1646 "CfgHostSerial: invalid input!");
1647 *dataLen = 0;
1648 return IPMI_CC_INVALID_FIELD_REQUEST;
1649 }
1650
1651 return IPMI_CC_OK;
1652}
1653
James Feist91244a62019-02-19 15:04:54 -08001654constexpr const char* thermalModeInterface =
1655 "xyz.openbmc_project.Control.ThermalMode";
1656constexpr const char* thermalModePath =
1657 "/xyz/openbmc_project/control/thermal_mode";
1658
1659bool getFanProfileInterface(
Patrick Williamsf944d2e2022-07-22 19:26:52 -05001660 sdbusplus::bus_t& bus,
Jason M. Bills0748c692022-09-08 15:34:08 -07001661 boost::container::flat_map<std::string, ipmi::DbusVariant>& resp)
James Feist91244a62019-02-19 15:04:54 -08001662{
1663 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1664 "GetAll");
1665 call.append(thermalModeInterface);
1666 try
1667 {
1668 auto data = bus.call(call);
1669 data.read(resp);
1670 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001671 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001672 {
1673 phosphor::logging::log<phosphor::logging::level::ERR>(
1674 "getFanProfileInterface: can't get thermal mode!",
1675 phosphor::logging::entry("ERR=%s", e.what()));
1676 return false;
1677 }
1678 return true;
1679}
1680
anil kumar appanaf945eee2019-09-25 23:29:11 +00001681/**@brief implements the OEM set fan config.
1682 * @param selectedFanProfile - fan profile to enable
1683 * @param reserved1
1684 * @param performanceMode - Performance/Acoustic mode
1685 * @param reserved2
1686 * @param setPerformanceMode - set Performance/Acoustic mode
1687 * @param setFanProfile - set fan profile
1688 *
1689 * @return IPMI completion code.
1690 **/
1691ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1692
1693 uint2_t reserved1, bool performanceMode,
1694 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301695 bool setFanProfile,
1696 std::optional<uint8_t> dimmGroupId,
1697 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001698{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001699 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001700 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001701 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001702 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301703
1704 if (dimmGroupId)
1705 {
1706 if (*dimmGroupId >= maxCPUNum)
1707 {
1708 return ipmi::responseInvalidFieldRequest();
1709 }
1710 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1711 {
1712 return ipmi::responseInvalidFieldRequest();
1713 }
1714 }
1715
James Feist91244a62019-02-19 15:04:54 -08001716 // todo: tell bios to only send first 2 bytes
Jason M. Bills0748c692022-09-08 15:34:08 -07001717 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001718 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1719 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001720 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001721 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001722 }
1723
1724 std::vector<std::string>* supported =
1725 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1726 if (supported == nullptr)
1727 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001728 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001729 }
1730 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001731 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001732 {
James Feist91244a62019-02-19 15:04:54 -08001733 if (performanceMode)
1734 {
1735
1736 if (std::find(supported->begin(), supported->end(),
1737 "Performance") != supported->end())
1738 {
1739 mode = "Performance";
1740 }
1741 }
1742 else
1743 {
James Feist91244a62019-02-19 15:04:54 -08001744 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1745 supported->end())
1746 {
1747 mode = "Acoustic";
1748 }
1749 }
1750 if (mode.empty())
1751 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001752 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001753 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001754
1755 try
1756 {
1757 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1758 thermalModeInterface, "Current", mode);
1759 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001760 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001761 {
1762 phosphor::logging::log<phosphor::logging::level::ERR>(
1763 "ipmiOEMSetFanConfig: can't set thermal mode!",
1764 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1765 return ipmi::responseResponseError();
1766 }
James Feist91244a62019-02-19 15:04:54 -08001767 }
1768
anil kumar appanaf945eee2019-09-25 23:29:11 +00001769 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001770}
1771
James Feist5b693632019-07-09 09:06:09 -07001772ipmi::RspType<uint8_t, // profile support map
1773 uint8_t, // fan control profile enable
1774 uint8_t, // flags
1775 uint32_t // dimm presence bit map
1776 >
1777 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001778{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301779 if (dimmGroupId >= maxCPUNum)
1780 {
1781 return ipmi::responseInvalidFieldRequest();
1782 }
1783
1784 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1785
1786 if (!cpuStatus)
1787 {
1788 return ipmi::responseInvalidFieldRequest();
1789 }
1790
Jason M. Bills0748c692022-09-08 15:34:08 -07001791 boost::container::flat_map<std::string, ipmi::DbusVariant> profileData;
James Feist91244a62019-02-19 15:04:54 -08001792
Vernon Mauery15419dd2019-05-24 09:40:30 -07001793 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1794 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001795 {
James Feist5b693632019-07-09 09:06:09 -07001796 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001797 }
1798
1799 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1800
1801 if (current == nullptr)
1802 {
1803 phosphor::logging::log<phosphor::logging::level::ERR>(
1804 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001805 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001806 }
1807 bool performance = (*current == "Performance");
1808
James Feist5b693632019-07-09 09:06:09 -07001809 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001810 if (performance)
1811 {
James Feist5b693632019-07-09 09:06:09 -07001812 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001813 }
1814
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001815 constexpr uint8_t fanControlDefaultProfile = 0x80;
1816 constexpr uint8_t fanControlProfileState = 0x00;
1817 constexpr uint32_t dimmPresenceBitmap = 0x00;
1818
1819 return ipmi::responseSuccess(fanControlDefaultProfile,
1820 fanControlProfileState, flags,
1821 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001822}
James Feist5f957ca2019-03-14 15:33:55 -07001823constexpr const char* cfmLimitSettingPath =
1824 "/xyz/openbmc_project/control/cfm_limit";
1825constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001826constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001827constexpr const size_t legacyPCHSensorNumber = 0x22;
1828constexpr const char* exitAirPathName = "Exit_Air";
1829constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001830constexpr const char* pidConfigurationIface =
1831 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001832
James Feist09f6b602019-08-08 11:30:03 -07001833static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001834{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001835 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001836 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001837 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1838 "/xyz/openbmc_project/object_mapper",
1839 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001840
James Feistacc8a4e2019-04-02 14:23:57 -07001841 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001842 std::string path;
1843 GetSubTreeType resp;
1844 try
1845 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001846 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001847 reply.read(resp);
1848 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001849 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001850 {
1851 phosphor::logging::log<phosphor::logging::level::ERR>(
1852 "ipmiOEMGetFscParameter: mapper error");
1853 };
James Feist09f6b602019-08-08 11:30:03 -07001854 auto config =
1855 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1856 return pair.first.find(name) != std::string::npos;
1857 });
James Feistfaa4f222019-03-21 16:21:55 -07001858 if (config != resp.end())
1859 {
1860 path = std::move(config->first);
1861 }
1862 return path;
1863}
James Feist5f957ca2019-03-14 15:33:55 -07001864
James Feistacc8a4e2019-04-02 14:23:57 -07001865// flat map to make alphabetical
1866static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1867{
1868 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001869 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001870 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001871 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1872 "/xyz/openbmc_project/object_mapper",
1873 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001874
1875 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1876 GetSubTreeType resp;
1877
1878 try
1879 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001880 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001881 reply.read(resp);
1882 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001883 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001884 {
1885 phosphor::logging::log<phosphor::logging::level::ERR>(
1886 "getFanConfigPaths: mapper error");
1887 };
1888 for (const auto& [path, objects] : resp)
1889 {
1890 if (objects.empty())
1891 {
1892 continue; // should be impossible
1893 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001894
1895 try
1896 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001897 ret.emplace(path,
1898 getAllDbusProperties(*dbus, objects[0].first, path,
1899 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001900 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001901 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001902 {
1903 phosphor::logging::log<phosphor::logging::level::ERR>(
1904 "getPidConfigs: can't get DbusProperties!",
1905 phosphor::logging::entry("ERR=%s", e.what()));
1906 }
James Feistacc8a4e2019-04-02 14:23:57 -07001907 }
1908 return ret;
1909}
1910
1911ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1912{
1913 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1914 if (data.empty())
1915 {
1916 return ipmi::responseResponseError();
1917 }
1918 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1919 for (const auto& [_, pid] : data)
1920 {
1921 auto findClass = pid.find("Class");
1922 if (findClass == pid.end())
1923 {
1924 phosphor::logging::log<phosphor::logging::level::ERR>(
1925 "ipmiOEMGetFscParameter: found illegal pid "
1926 "configurations");
1927 return ipmi::responseResponseError();
1928 }
1929 std::string type = std::get<std::string>(findClass->second);
1930 if (type == "fan")
1931 {
1932 auto findOutLimit = pid.find("OutLimitMin");
1933 if (findOutLimit == pid.end())
1934 {
1935 phosphor::logging::log<phosphor::logging::level::ERR>(
1936 "ipmiOEMGetFscParameter: found illegal pid "
1937 "configurations");
1938 return ipmi::responseResponseError();
1939 }
1940 // get the min out of all the offsets
1941 minOffset = std::min(
1942 minOffset,
1943 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1944 }
1945 }
1946 if (minOffset == std::numeric_limits<uint8_t>::max())
1947 {
1948 phosphor::logging::log<phosphor::logging::level::ERR>(
1949 "ipmiOEMGetFscParameter: found no fan configurations!");
1950 return ipmi::responseResponseError();
1951 }
1952
1953 return ipmi::responseSuccess(minOffset);
1954}
1955
1956ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1957{
Manish Baingbaa579f2021-10-08 22:30:32 +00001958 constexpr uint8_t maxFanSpeedOffset = 100;
1959 if (offset > maxFanSpeedOffset)
1960 {
1961 phosphor::logging::log<phosphor::logging::level::ERR>(
1962 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1963 return ipmi::responseInvalidFieldRequest();
1964 }
James Feistacc8a4e2019-04-02 14:23:57 -07001965 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1966 if (data.empty())
1967 {
1968
1969 phosphor::logging::log<phosphor::logging::level::ERR>(
1970 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1971 return ipmi::responseResponseError();
1972 }
1973
Vernon Mauery15419dd2019-05-24 09:40:30 -07001974 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001975 bool found = false;
1976 for (const auto& [path, pid] : data)
1977 {
1978 auto findClass = pid.find("Class");
1979 if (findClass == pid.end())
1980 {
1981
1982 phosphor::logging::log<phosphor::logging::level::ERR>(
1983 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1984 "configurations");
1985 return ipmi::responseResponseError();
1986 }
1987 std::string type = std::get<std::string>(findClass->second);
1988 if (type == "fan")
1989 {
1990 auto findOutLimit = pid.find("OutLimitMin");
1991 if (findOutLimit == pid.end())
1992 {
1993
1994 phosphor::logging::log<phosphor::logging::level::ERR>(
1995 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1996 "configurations");
1997 return ipmi::responseResponseError();
1998 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001999 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07002000 path, pidConfigurationIface, "OutLimitMin",
2001 static_cast<double>(offset));
2002 found = true;
2003 }
2004 }
2005 if (!found)
2006 {
2007 phosphor::logging::log<phosphor::logging::level::ERR>(
2008 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
2009 return ipmi::responseResponseError();
2010 }
2011
2012 return ipmi::responseSuccess();
2013}
2014
2015ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
2016 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07002017{
2018 constexpr const size_t disableLimiting = 0x0;
2019
Vernon Mauery15419dd2019-05-24 09:40:30 -07002020 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002021 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002022 {
James Feist09f6b602019-08-08 11:30:03 -07002023 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07002024 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07002025 {
James Feist09f6b602019-08-08 11:30:03 -07002026 pathName = exitAirPathName;
2027 }
2028 else if (param1 == legacyPCHSensorNumber)
2029 {
2030 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07002031 }
2032 else
2033 {
James Feistacc8a4e2019-04-02 14:23:57 -07002034 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002035 }
James Feist09f6b602019-08-08 11:30:03 -07002036 std::string path = getConfigPath(pathName);
2037 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
2038 pidConfigurationIface, "SetPoint",
2039 static_cast<double>(param2));
2040 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07002041 }
James Feistacc8a4e2019-04-02 14:23:57 -07002042 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002043 {
James Feistacc8a4e2019-04-02 14:23:57 -07002044 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07002045
2046 // must be greater than 50 based on eps
2047 if (cfm < 50 && cfm != disableLimiting)
2048 {
James Feistacc8a4e2019-04-02 14:23:57 -07002049 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002050 }
2051
2052 try
2053 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002054 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07002055 cfmLimitIface, "Limit",
2056 static_cast<double>(cfm));
2057 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002058 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002059 {
2060 phosphor::logging::log<phosphor::logging::level::ERR>(
2061 "ipmiOEMSetFscParameter: can't set cfm setting!",
2062 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002063 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002064 }
James Feistacc8a4e2019-04-02 14:23:57 -07002065 return ipmi::responseSuccess();
2066 }
2067 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2068 {
2069 constexpr const size_t maxDomainCount = 8;
2070 uint8_t requestedDomainMask = param1;
2071 boost::container::flat_map data = getPidConfigs();
2072 if (data.empty())
2073 {
2074
2075 phosphor::logging::log<phosphor::logging::level::ERR>(
2076 "ipmiOEMSetFscParameter: found no pid configurations!");
2077 return ipmi::responseResponseError();
2078 }
2079 size_t count = 0;
2080 for (const auto& [path, pid] : data)
2081 {
2082 auto findClass = pid.find("Class");
2083 if (findClass == pid.end())
2084 {
2085
2086 phosphor::logging::log<phosphor::logging::level::ERR>(
2087 "ipmiOEMSetFscParameter: found illegal pid "
2088 "configurations");
2089 return ipmi::responseResponseError();
2090 }
2091 std::string type = std::get<std::string>(findClass->second);
2092 if (type == "fan")
2093 {
2094 if (requestedDomainMask & (1 << count))
2095 {
2096 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002097 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07002098 pidConfigurationIface, "OutLimitMax",
2099 static_cast<double>(param2));
2100 }
2101 count++;
2102 }
2103 }
2104 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07002105 }
2106 else
2107 {
2108 // todo other command parts possibly
2109 // tcontrol is handled in peci now
2110 // fan speed offset not implemented yet
2111 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002112 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002113 }
2114}
2115
James Feistacc8a4e2019-04-02 14:23:57 -07002116ipmi::RspType<
2117 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2118 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002119{
James Feist09f6b602019-08-08 11:30:03 -07002120 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002121
Vernon Mauery15419dd2019-05-24 09:40:30 -07002122 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002123 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002124 {
James Feistacc8a4e2019-04-02 14:23:57 -07002125 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002126 {
James Feistacc8a4e2019-04-02 14:23:57 -07002127 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002128 }
2129
James Feist09f6b602019-08-08 11:30:03 -07002130 std::string pathName;
2131
2132 if (*param == legacyExitAirSensorNumber)
2133 {
2134 pathName = exitAirPathName;
2135 }
2136 else if (*param == legacyPCHSensorNumber)
2137 {
2138 pathName = pchPathName;
2139 }
2140 else
James Feistfaa4f222019-03-21 16:21:55 -07002141 {
James Feistacc8a4e2019-04-02 14:23:57 -07002142 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002143 }
James Feist09f6b602019-08-08 11:30:03 -07002144
2145 uint8_t setpoint = legacyDefaultSetpoint;
2146 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002147 if (path.size())
2148 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002149 Value val = ipmi::getDbusProperty(
2150 *dbus, "xyz.openbmc_project.EntityManager", path,
2151 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002152 setpoint = std::floor(std::get<double>(val) + 0.5);
2153 }
2154
2155 // old implementation used to return the "default" and current, we
2156 // don't make the default readily available so just make both the
2157 // same
James Feistfaa4f222019-03-21 16:21:55 -07002158
James Feistacc8a4e2019-04-02 14:23:57 -07002159 return ipmi::responseSuccess(
2160 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002161 }
James Feistacc8a4e2019-04-02 14:23:57 -07002162 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2163 {
2164 constexpr const size_t maxDomainCount = 8;
2165
2166 if (!param)
2167 {
2168 return ipmi::responseReqDataLenInvalid();
2169 }
2170 uint8_t requestedDomain = *param;
2171 if (requestedDomain >= maxDomainCount)
2172 {
2173 return ipmi::responseInvalidFieldRequest();
2174 }
2175
2176 boost::container::flat_map data = getPidConfigs();
2177 if (data.empty())
2178 {
2179 phosphor::logging::log<phosphor::logging::level::ERR>(
2180 "ipmiOEMGetFscParameter: found no pid configurations!");
2181 return ipmi::responseResponseError();
2182 }
2183 size_t count = 0;
2184 for (const auto& [_, pid] : data)
2185 {
2186 auto findClass = pid.find("Class");
2187 if (findClass == pid.end())
2188 {
2189 phosphor::logging::log<phosphor::logging::level::ERR>(
2190 "ipmiOEMGetFscParameter: found illegal pid "
2191 "configurations");
2192 return ipmi::responseResponseError();
2193 }
2194 std::string type = std::get<std::string>(findClass->second);
2195 if (type == "fan")
2196 {
2197 if (requestedDomain == count)
2198 {
2199 auto findOutLimit = pid.find("OutLimitMax");
2200 if (findOutLimit == pid.end())
2201 {
2202 phosphor::logging::log<phosphor::logging::level::ERR>(
2203 "ipmiOEMGetFscParameter: found illegal pid "
2204 "configurations");
2205 return ipmi::responseResponseError();
2206 }
2207
2208 return ipmi::responseSuccess(
2209 static_cast<uint8_t>(std::floor(
2210 std::get<double>(findOutLimit->second) + 0.5)));
2211 }
2212 else
2213 {
2214 count++;
2215 }
2216 }
2217 }
2218
2219 return ipmi::responseInvalidFieldRequest();
2220 }
2221 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002222 {
2223
2224 /*
2225 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002226 previous behavior didn't seem to prevent this, ignore the check for
2227 now.
James Feist5f957ca2019-03-14 15:33:55 -07002228
James Feistacc8a4e2019-04-02 14:23:57 -07002229 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002230 {
2231 phosphor::logging::log<phosphor::logging::level::ERR>(
2232 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002233 return IPMI_CC_REQ_DATA_LEN_INVALID;
2234 }
2235 */
2236 Value cfmLimit;
2237 Value cfmMaximum;
2238 try
2239 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002240 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002241 cfmLimitSettingPath, cfmLimitIface,
2242 "Limit");
2243 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002244 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002245 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2246 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002247 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002248 {
2249 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002250 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002251 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002252 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002253 }
2254
James Feistacc8a4e2019-04-02 14:23:57 -07002255 double cfmMax = std::get<double>(cfmMaximum);
2256 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002257
James Feistacc8a4e2019-04-02 14:23:57 -07002258 cfmLim = std::floor(cfmLim + 0.5);
2259 cfmMax = std::floor(cfmMax + 0.5);
2260 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2261 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002262
James Feistacc8a4e2019-04-02 14:23:57 -07002263 return ipmi::responseSuccess(
2264 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002265 }
James Feistacc8a4e2019-04-02 14:23:57 -07002266
James Feist5f957ca2019-03-14 15:33:55 -07002267 else
2268 {
2269 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002270 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002271 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002272 }
2273}
2274
Jason M. Bills0748c692022-09-08 15:34:08 -07002275using crConfigVariant = ipmi::DbusVariant;
Cheng C Yang773703a2019-08-15 09:41:11 +08002276
2277int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2278 const crConfigVariant& value,
2279 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2280{
2281 boost::system::error_code ec;
2282 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002283 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002284 "/xyz/openbmc_project/control/power_supply_redundancy",
2285 "org.freedesktop.DBus.Properties", "Set",
2286 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2287 if (ec)
2288 {
2289 phosphor::logging::log<phosphor::logging::level::ERR>(
2290 "Failed to set dbus property to cold redundancy");
2291 return -1;
2292 }
2293
2294 return 0;
2295}
2296
Kuiying Wange45333a2020-07-22 22:06:37 +08002297int getCRConfig(
2298 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2299 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2300 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002301{
2302 boost::system::error_code ec;
2303 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002304 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002305 "/xyz/openbmc_project/control/power_supply_redundancy",
2306 "org.freedesktop.DBus.Properties", "Get",
2307 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2308 if (ec)
2309 {
2310 phosphor::logging::log<phosphor::logging::level::ERR>(
2311 "Failed to get dbus property to cold redundancy");
2312 return -1;
2313 }
2314 return 0;
2315}
2316
2317uint8_t getPSUCount(void)
2318{
2319 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2320 ipmi::Value num;
2321 try
2322 {
2323 num = ipmi::getDbusProperty(
2324 *dbus, "xyz.openbmc_project.PSURedundancy",
2325 "/xyz/openbmc_project/control/power_supply_redundancy",
2326 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2327 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002328 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002329 {
2330 phosphor::logging::log<phosphor::logging::level::ERR>(
2331 "Failed to get PSUNumber property from dbus interface");
2332 return 0;
2333 }
2334 uint8_t* pNum = std::get_if<uint8_t>(&num);
2335 if (!pNum)
2336 {
2337 phosphor::logging::log<phosphor::logging::level::ERR>(
2338 "Error to get PSU Number");
2339 return 0;
2340 }
2341 return *pNum;
2342}
2343
2344bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2345{
2346 if (conf.size() < num)
2347 {
2348 phosphor::logging::log<phosphor::logging::level::ERR>(
2349 "Invalid PSU Ranking");
2350 return false;
2351 }
2352 std::set<uint8_t> confSet;
2353 for (uint8_t i = 0; i < num; i++)
2354 {
2355 if (conf[i] > num)
2356 {
2357 phosphor::logging::log<phosphor::logging::level::ERR>(
2358 "PSU Ranking is larger than current PSU number");
2359 return false;
2360 }
2361 confSet.emplace(conf[i]);
2362 }
2363
2364 if (confSet.size() != num)
2365 {
2366 phosphor::logging::log<phosphor::logging::level::ERR>(
2367 "duplicate PSU Ranking");
2368 return false;
2369 }
2370 return true;
2371}
2372
2373enum class crParameter
2374{
2375 crStatus = 0,
2376 crFeature = 1,
2377 rotationFeature = 2,
2378 rotationAlgo = 3,
2379 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002380 numOfPSU = 5,
2381 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002382};
2383
2384constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2385static const constexpr uint32_t oneDay = 0x15180;
2386static const constexpr uint32_t oneMonth = 0xf53700;
2387static const constexpr uint8_t userSpecific = 0x01;
2388static const constexpr uint8_t crSetCompleted = 0;
2389ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2390 uint8_t parameter,
2391 ipmi::message::Payload& payload)
2392{
2393 switch (static_cast<crParameter>(parameter))
2394 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002395 case crParameter::rotationFeature:
2396 {
2397 uint8_t param1;
2398 if (payload.unpack(param1) || !payload.fullyUnpacked())
2399 {
2400 return ipmi::responseReqDataLenInvalid();
2401 }
2402 // Rotation Enable can only be true or false
2403 if (param1 > 1)
2404 {
2405 return ipmi::responseInvalidFieldRequest();
2406 }
2407 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2408 {
2409 return ipmi::responseResponseError();
2410 }
2411 break;
2412 }
2413 case crParameter::rotationAlgo:
2414 {
2415 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2416 std::string algoName;
2417 uint8_t param1;
2418 if (payload.unpack(param1))
2419 {
2420 return ipmi::responseReqDataLenInvalid();
2421 }
2422 switch (param1)
2423 {
2424 case 0:
2425 algoName = "xyz.openbmc_project.Control."
2426 "PowerSupplyRedundancy.Algo.bmcSpecific";
2427 break;
2428 case 1:
2429 algoName = "xyz.openbmc_project.Control."
2430 "PowerSupplyRedundancy.Algo.userSpecific";
2431 break;
2432 default:
2433 return ipmi::responseInvalidFieldRequest();
2434 }
2435 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2436 {
2437 return ipmi::responseResponseError();
2438 }
2439
2440 uint8_t numberOfPSU = getPSUCount();
2441 if (!numberOfPSU)
2442 {
2443 return ipmi::responseResponseError();
2444 }
2445 std::vector<uint8_t> rankOrder;
2446
2447 if (param1 == userSpecific)
2448 {
2449 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2450 {
2451 ipmi::responseReqDataLenInvalid();
2452 }
Yong Li83315132019-10-23 17:42:24 +08002453 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002454 {
2455 return ipmi::responseReqDataLenInvalid();
2456 }
2457
2458 if (!validateCRAlgo(rankOrder, numberOfPSU))
2459 {
2460 return ipmi::responseInvalidFieldRequest();
2461 }
2462 }
2463 else
2464 {
2465 if (rankOrder.size() > 0)
2466 {
2467 return ipmi::responseReqDataLenInvalid();
2468 }
2469 for (uint8_t i = 1; i <= numberOfPSU; i++)
2470 {
2471 rankOrder.emplace_back(i);
2472 }
2473 }
2474 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2475 {
2476 return ipmi::responseResponseError();
2477 }
2478 break;
2479 }
2480 case crParameter::rotationPeriod:
2481 {
2482 // Minimum Rotation period is One day (86400 seconds) and Max
2483 // Rotation Period is 6 month (0xf53700 seconds)
2484 uint32_t period;
2485 if (payload.unpack(period) || !payload.fullyUnpacked())
2486 {
2487 return ipmi::responseReqDataLenInvalid();
2488 }
2489 if ((period < oneDay) || (period > oneMonth))
2490 {
2491 return ipmi::responseInvalidFieldRequest();
2492 }
2493 if (setCRConfig(ctx, "PeriodOfRotation", period))
2494 {
2495 return ipmi::responseResponseError();
2496 }
2497 break;
2498 }
2499 default:
2500 {
2501 return ipmi::response(ccParameterNotSupported);
2502 }
2503 }
2504
Cheng C Yang773703a2019-08-15 09:41:11 +08002505 return ipmi::responseSuccess(crSetCompleted);
2506}
2507
Yong Li83315132019-10-23 17:42:24 +08002508ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002509 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2510{
2511 crConfigVariant value;
2512 switch (static_cast<crParameter>(parameter))
2513 {
2514 case crParameter::crStatus:
2515 {
2516 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2517 {
2518 return ipmi::responseResponseError();
2519 }
2520 std::string* pStatus = std::get_if<std::string>(&value);
2521 if (!pStatus)
2522 {
2523 phosphor::logging::log<phosphor::logging::level::ERR>(
2524 "Error to get ColdRedundancyStatus property");
2525 return ipmi::responseResponseError();
2526 }
2527 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2528 auto status =
2529 server::PowerSupplyRedundancy::convertStatusFromString(
2530 *pStatus);
2531 switch (status)
2532 {
2533 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002534 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002535 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002536
2537 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002538 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002539 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002540 default:
2541 phosphor::logging::log<phosphor::logging::level::ERR>(
2542 "Error to get valid status");
2543 return ipmi::responseResponseError();
2544 }
2545 }
2546 case crParameter::crFeature:
2547 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002548 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002549 {
2550 return ipmi::responseResponseError();
2551 }
2552 bool* pResponse = std::get_if<bool>(&value);
2553 if (!pResponse)
2554 {
2555 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002556 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002557 return ipmi::responseResponseError();
2558 }
2559
Cheng C Yangf41e3342019-09-10 04:47:23 +08002560 return ipmi::responseSuccess(parameter,
2561 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002562 }
2563 case crParameter::rotationFeature:
2564 {
2565 if (getCRConfig(ctx, "RotationEnabled", value))
2566 {
2567 return ipmi::responseResponseError();
2568 }
2569 bool* pResponse = std::get_if<bool>(&value);
2570 if (!pResponse)
2571 {
2572 phosphor::logging::log<phosphor::logging::level::ERR>(
2573 "Error to get RotationEnabled property");
2574 return ipmi::responseResponseError();
2575 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002576 return ipmi::responseSuccess(parameter,
2577 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002578 }
2579 case crParameter::rotationAlgo:
2580 {
2581 if (getCRConfig(ctx, "RotationAlgorithm", value))
2582 {
2583 return ipmi::responseResponseError();
2584 }
2585
2586 std::string* pAlgo = std::get_if<std::string>(&value);
2587 if (!pAlgo)
2588 {
2589 phosphor::logging::log<phosphor::logging::level::ERR>(
2590 "Error to get RotationAlgorithm property");
2591 return ipmi::responseResponseError();
2592 }
Yong Li83315132019-10-23 17:42:24 +08002593 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002594 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2595 auto algo =
2596 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002597
Cheng C Yang773703a2019-08-15 09:41:11 +08002598 switch (algo)
2599 {
2600 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002601 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002602 break;
2603 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002604 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002605 break;
2606 default:
2607 phosphor::logging::log<phosphor::logging::level::ERR>(
2608 "Error to get valid algo");
2609 return ipmi::responseResponseError();
2610 }
2611
2612 if (getCRConfig(ctx, "RotationRankOrder", value))
2613 {
2614 return ipmi::responseResponseError();
2615 }
2616 std::vector<uint8_t>* pResponse =
2617 std::get_if<std::vector<uint8_t>>(&value);
2618 if (!pResponse)
2619 {
2620 phosphor::logging::log<phosphor::logging::level::ERR>(
2621 "Error to get RotationRankOrder property");
2622 return ipmi::responseResponseError();
2623 }
Yong Li83315132019-10-23 17:42:24 +08002624
Cheng C Yang773703a2019-08-15 09:41:11 +08002625 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002626 std::back_inserter(response));
2627
Cheng C Yangf41e3342019-09-10 04:47:23 +08002628 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002629 }
2630 case crParameter::rotationPeriod:
2631 {
2632 if (getCRConfig(ctx, "PeriodOfRotation", value))
2633 {
2634 return ipmi::responseResponseError();
2635 }
2636 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2637 if (!pResponse)
2638 {
2639 phosphor::logging::log<phosphor::logging::level::ERR>(
2640 "Error to get RotationAlgorithm property");
2641 return ipmi::responseResponseError();
2642 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002643 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002644 }
2645 case crParameter::numOfPSU:
2646 {
2647 uint8_t numberOfPSU = getPSUCount();
2648 if (!numberOfPSU)
2649 {
2650 return ipmi::responseResponseError();
2651 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002652 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002653 }
Yong Li19445ab2019-12-20 18:25:29 +08002654 case crParameter::rotationRankOrderEffective:
2655 {
2656 if (getCRConfig(ctx, "RotationRankOrder", value,
2657 "xyz.openbmc_project.PSURedundancy"))
2658 {
2659 return ipmi::responseResponseError();
2660 }
2661 std::vector<uint8_t>* pResponse =
2662 std::get_if<std::vector<uint8_t>>(&value);
2663 if (!pResponse)
2664 {
2665 phosphor::logging::log<phosphor::logging::level::ERR>(
2666 "Error to get effective RotationRankOrder property");
2667 return ipmi::responseResponseError();
2668 }
2669 return ipmi::responseSuccess(parameter, *pResponse);
2670 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002671 default:
2672 {
2673 return ipmi::response(ccParameterNotSupported);
2674 }
2675 }
2676}
2677
Zhu, Yungebe560b02019-04-21 21:19:21 -04002678ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2679 uint8_t faultState,
2680 uint8_t faultGroup,
2681 std::array<uint8_t, 8>& ledStateData)
2682{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002683 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2684 static const std::array<std::string, maxFaultType> faultNames = {
2685 "faultFan", "faultTemp", "faultPower",
2686 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002687
2688 constexpr uint8_t maxFaultSource = 0x4;
2689 constexpr uint8_t skipLEDs = 0xFF;
2690 constexpr uint8_t pinSize = 64;
2691 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002692 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002693
Zhikui Rence4e73f2019-12-06 13:59:47 -08002694 // same pin names need to be defined in dts file
2695 static const std::array<std::array<std::string, groupSize>, groupNum>
2696 faultLedPinNames = {{
2697 "LED_CPU1_CH1_DIMM1_FAULT",
2698 "LED_CPU1_CH1_DIMM2_FAULT",
2699 "LED_CPU1_CH2_DIMM1_FAULT",
2700 "LED_CPU1_CH2_DIMM2_FAULT",
2701 "LED_CPU1_CH3_DIMM1_FAULT",
2702 "LED_CPU1_CH3_DIMM2_FAULT",
2703 "LED_CPU1_CH4_DIMM1_FAULT",
2704 "LED_CPU1_CH4_DIMM2_FAULT",
2705 "LED_CPU1_CH5_DIMM1_FAULT",
2706 "LED_CPU1_CH5_DIMM2_FAULT",
2707 "LED_CPU1_CH6_DIMM1_FAULT",
2708 "LED_CPU1_CH6_DIMM2_FAULT",
2709 "",
2710 "",
2711 "",
2712 "", // end of group1
2713 "LED_CPU2_CH1_DIMM1_FAULT",
2714 "LED_CPU2_CH1_DIMM2_FAULT",
2715 "LED_CPU2_CH2_DIMM1_FAULT",
2716 "LED_CPU2_CH2_DIMM2_FAULT",
2717 "LED_CPU2_CH3_DIMM1_FAULT",
2718 "LED_CPU2_CH3_DIMM2_FAULT",
2719 "LED_CPU2_CH4_DIMM1_FAULT",
2720 "LED_CPU2_CH4_DIMM2_FAULT",
2721 "LED_CPU2_CH5_DIMM1_FAULT",
2722 "LED_CPU2_CH5_DIMM2_FAULT",
2723 "LED_CPU2_CH6_DIMM1_FAULT",
2724 "LED_CPU2_CH6_DIMM2_FAULT",
2725 "",
2726 "",
2727 "",
2728 "", // endof group2
2729 "LED_CPU3_CH1_DIMM1_FAULT",
2730 "LED_CPU3_CH1_DIMM2_FAULT",
2731 "LED_CPU3_CH2_DIMM1_FAULT",
2732 "LED_CPU3_CH2_DIMM2_FAULT",
2733 "LED_CPU3_CH3_DIMM1_FAULT",
2734 "LED_CPU3_CH3_DIMM2_FAULT",
2735 "LED_CPU3_CH4_DIMM1_FAULT",
2736 "LED_CPU3_CH4_DIMM2_FAULT",
2737 "LED_CPU3_CH5_DIMM1_FAULT",
2738 "LED_CPU3_CH5_DIMM2_FAULT",
2739 "LED_CPU3_CH6_DIMM1_FAULT",
2740 "LED_CPU3_CH6_DIMM2_FAULT",
2741 "",
2742 "",
2743 "",
2744 "", // end of group3
2745 "LED_CPU4_CH1_DIMM1_FAULT",
2746 "LED_CPU4_CH1_DIMM2_FAULT",
2747 "LED_CPU4_CH2_DIMM1_FAULT",
2748 "LED_CPU4_CH2_DIMM2_FAULT",
2749 "LED_CPU4_CH3_DIMM1_FAULT",
2750 "LED_CPU4_CH3_DIMM2_FAULT",
2751 "LED_CPU4_CH4_DIMM1_FAULT",
2752 "LED_CPU4_CH4_DIMM2_FAULT",
2753 "LED_CPU4_CH5_DIMM1_FAULT",
2754 "LED_CPU4_CH5_DIMM2_FAULT",
2755 "LED_CPU4_CH6_DIMM1_FAULT",
2756 "LED_CPU4_CH6_DIMM2_FAULT",
2757 "",
2758 "",
2759 "",
2760 "", // end of group4
2761 "LED_FAN1_FAULT",
2762 "LED_FAN2_FAULT",
2763 "LED_FAN3_FAULT",
2764 "LED_FAN4_FAULT",
2765 "LED_FAN5_FAULT",
2766 "LED_FAN6_FAULT",
2767 "LED_FAN7_FAULT",
2768 "LED_FAN8_FAULT",
2769 "",
2770 "",
2771 "",
2772 "",
2773 "",
2774 "",
2775 "",
2776 "" // end of group5
2777 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002778
Zhikui Rence4e73f2019-12-06 13:59:47 -08002779 // Validate the source, fault type --
2780 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2781 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2782 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2783 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2784 // definition differs based on fault type (Byte 2)
2785 // Type Fan=> Group: 0=FanGroupID, FF-not used
2786 // Byte 5-11 00h, not used
2787 // Byte12 FanLedState [7:0]-Fans 7:0
2788 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2789 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2790 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2791 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2792 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2793 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2794 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2795 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002796 if ((sourceId >= maxFaultSource) ||
2797 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2798 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2799 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2800 {
2801 return ipmi::responseParmOutOfRange();
2802 }
2803
Zhikui Rence4e73f2019-12-06 13:59:47 -08002804 size_t pinGroupOffset = 0;
2805 size_t pinGroupMax = pinSize / groupSize;
2806 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002807 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002808 pinGroupOffset = 4;
2809 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002810 }
2811
2812 switch (RemoteFaultType(faultType))
2813 {
2814 case (RemoteFaultType::fan):
2815 case (RemoteFaultType::memory):
2816 {
2817 if (faultGroup == skipLEDs)
2818 {
2819 return ipmi::responseSuccess();
2820 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002821 // calculate led state bit filed count, each byte has 8bits
2822 // the maximum bits will be 8 * 8 bits
2823 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002824
2825 // assemble ledState
2826 uint64_t ledState = 0;
2827 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002828 for (int i = 0; i < sizeof(ledStateData); i++)
2829 {
2830 ledState = (uint64_t)(ledState << 8);
2831 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2832 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002833 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002834
Zhikui Rence4e73f2019-12-06 13:59:47 -08002835 for (int group = 0; group < pinGroupMax; group++)
2836 {
2837 for (int i = 0; i < groupSize; i++)
2838 { // skip non-existing pins
2839 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2840 {
2841 continue;
2842 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002843
Zhikui Rence4e73f2019-12-06 13:59:47 -08002844 gpiod::line line = gpiod::find_line(
2845 faultLedPinNames[group + pinGroupOffset][i]);
2846 if (!line)
2847 {
2848 phosphor::logging::log<phosphor::logging::level::ERR>(
2849 "Not Find Led Gpio Device!",
2850 phosphor::logging::entry(
2851 "DEVICE=%s",
2852 faultLedPinNames[group + pinGroupOffset][i]
2853 .c_str()));
2854 hasError = true;
2855 continue;
2856 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002857
Zhikui Rence4e73f2019-12-06 13:59:47 -08002858 bool activeHigh =
2859 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2860 try
2861 {
2862 line.request(
2863 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2864 activeHigh
2865 ? 0
2866 : gpiod::line_request::FLAG_ACTIVE_LOW});
2867 line.set_value(ledStateBits[i + group * groupSize]);
2868 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002869 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002870 {
2871 phosphor::logging::log<phosphor::logging::level::ERR>(
2872 "Error write Led Gpio Device!",
2873 phosphor::logging::entry(
2874 "DEVICE=%s",
2875 faultLedPinNames[group + pinGroupOffset][i]
2876 .c_str()));
2877 hasError = true;
2878 continue;
2879 }
2880 } // for int i
2881 }
2882 if (hasError)
2883 {
2884 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002885 }
2886 break;
2887 }
2888 default:
2889 {
2890 // now only support two fault types
2891 return ipmi::responseParmOutOfRange();
2892 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002893 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002894 return ipmi::responseSuccess();
2895}
2896
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302897ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2898{
2899 uint8_t prodId = 0;
2900 try
2901 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002902 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302903 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002904 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302905 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2906 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002907 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302908 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2909 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302910 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2911 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002912 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302913 {
2914 phosphor::logging::log<phosphor::logging::level::ERR>(
2915 "ipmiOEMReadBoardProductId: Product ID read failed!",
2916 phosphor::logging::entry("ERR=%s", e.what()));
2917 }
2918 return ipmi::responseSuccess(prodId);
2919}
2920
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302921/** @brief implements the get security mode command
2922 * @param ctx - ctx pointer
2923 *
2924 * @returns IPMI completion code with following data
2925 * - restriction mode value - As specified in
2926 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2927 * - special mode value - As specified in
2928 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2929 */
2930ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2931{
2932 namespace securityNameSpace =
2933 sdbusplus::xyz::openbmc_project::Control::Security::server;
2934 uint8_t restrictionModeValue = 0;
2935 uint8_t specialModeValue = 0;
2936
2937 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07002938 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07002939 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302940 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2941 restricionModeProperty);
2942 if (ec)
2943 {
2944 phosphor::logging::log<phosphor::logging::level::ERR>(
2945 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2946 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2947 return ipmi::responseUnspecifiedError();
2948 }
2949 restrictionModeValue = static_cast<uint8_t>(
2950 securityNameSpace::RestrictionMode::convertModesFromString(
2951 std::get<std::string>(varRestrMode)));
Jason M. Bills0748c692022-09-08 15:34:08 -07002952 auto varSpecialMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
2953 ctx->yield, ec, specialModeService, specialModeBasePath,
2954 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2955 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302956 if (ec)
2957 {
2958 phosphor::logging::log<phosphor::logging::level::ERR>(
2959 "ipmiGetSecurityMode: failed to get SpecialMode property",
2960 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2961 // fall through, let us not worry about SpecialMode property, which is
2962 // not required in user scenario
2963 }
2964 else
2965 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302966 specialModeValue = static_cast<uint8_t>(
2967 securityNameSpace::SpecialMode::convertModesFromString(
2968 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302969 }
2970 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2971}
2972
2973/** @brief implements the set security mode command
2974 * Command allows to upgrade the restriction mode and won't allow
2975 * to downgrade from system interface
2976 * @param ctx - ctx pointer
2977 * @param restrictionMode - restriction mode value to be set.
2978 *
2979 * @returns IPMI completion code
2980 */
2981ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302982 uint8_t restrictionMode,
2983 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302984{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302985#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2986 if (specialMode)
2987 {
2988 return ipmi::responseReqDataLenInvalid();
2989 }
2990#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302991 namespace securityNameSpace =
2992 sdbusplus::xyz::openbmc_project::Control::Security::server;
2993
2994 ChannelInfo chInfo;
2995 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2996 {
2997 phosphor::logging::log<phosphor::logging::level::ERR>(
2998 "ipmiSetSecurityMode: Failed to get Channel Info",
2999 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
3000 return ipmi::responseUnspecifiedError();
3001 }
3002 auto reqMode =
3003 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
3004
3005 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
3006 (reqMode >
3007 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
3008 {
3009 return ipmi::responseInvalidFieldRequest();
3010 }
3011
3012 boost::system::error_code ec;
Jason M. Bills0748c692022-09-08 15:34:08 -07003013 auto varRestrMode = ctx->bus->yield_method_call<ipmi::DbusVariant>(
James Feist28c72902019-09-16 10:34:07 -07003014 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303015 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
3016 restricionModeProperty);
3017 if (ec)
3018 {
3019 phosphor::logging::log<phosphor::logging::level::ERR>(
3020 "ipmiSetSecurityMode: failed to get RestrictionMode property",
3021 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3022 return ipmi::responseUnspecifiedError();
3023 }
3024 auto currentRestrictionMode =
3025 securityNameSpace::RestrictionMode::convertModesFromString(
3026 std::get<std::string>(varRestrMode));
3027
3028 if (chInfo.mediumType !=
3029 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
3030 currentRestrictionMode > reqMode)
3031 {
3032 phosphor::logging::log<phosphor::logging::level::ERR>(
3033 "ipmiSetSecurityMode - Downgrading security mode not supported "
3034 "through system interface",
3035 phosphor::logging::entry(
3036 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
3037 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
3038 return ipmi::responseCommandNotAvailable();
3039 }
3040
3041 ec.clear();
3042 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07003043 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303044 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
3045 restricionModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003046 static_cast<ipmi::DbusVariant>(
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303047 securityNameSpace::convertForMessage(reqMode)));
3048
3049 if (ec)
3050 {
3051 phosphor::logging::log<phosphor::logging::level::ERR>(
3052 "ipmiSetSecurityMode: failed to set RestrictionMode property",
3053 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3054 return ipmi::responseUnspecifiedError();
3055 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303056
3057#ifdef BMC_VALIDATION_UNSECURE_FEATURE
3058 if (specialMode)
3059 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00003060 constexpr uint8_t mfgMode = 0x01;
3061 // Manufacturing mode is reserved. So can't enable this mode.
3062 if (specialMode.value() == mfgMode)
3063 {
3064 phosphor::logging::log<phosphor::logging::level::INFO>(
3065 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
3066 return ipmi::responseInvalidFieldRequest();
3067 }
3068
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303069 ec.clear();
3070 ctx->bus->yield_method_call<>(
3071 ctx->yield, ec, specialModeService, specialModeBasePath,
3072 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
3073 specialModeProperty,
Jason M. Bills0748c692022-09-08 15:34:08 -07003074 static_cast<ipmi::DbusVariant>(securityNameSpace::convertForMessage(
3075 static_cast<securityNameSpace::SpecialMode::Modes>(
3076 specialMode.value()))));
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303077
3078 if (ec)
3079 {
3080 phosphor::logging::log<phosphor::logging::level::ERR>(
3081 "ipmiSetSecurityMode: failed to set SpecialMode property",
3082 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3083 return ipmi::responseUnspecifiedError();
3084 }
3085 }
3086#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303087 return ipmi::responseSuccess();
3088}
3089
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003090ipmi::RspType<uint8_t /* restore status */>
3091 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
3092{
3093 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
3094
3095 if (clr != expClr)
3096 {
3097 return ipmi::responseInvalidFieldRequest();
3098 }
3099 constexpr uint8_t cmdStatus = 0;
3100 constexpr uint8_t cmdDefaultRestore = 0xaa;
3101 constexpr uint8_t cmdFullRestore = 0xbb;
3102 constexpr uint8_t cmdFormat = 0xcc;
3103
3104 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3105
3106 switch (cmd)
3107 {
3108 case cmdStatus:
3109 break;
3110 case cmdDefaultRestore:
3111 case cmdFullRestore:
3112 case cmdFormat:
3113 {
3114 // write file to rwfs root
3115 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3116 std::ofstream restoreFile(restoreOpFname);
3117 if (!restoreFile)
3118 {
3119 return ipmi::responseUnspecifiedError();
3120 }
3121 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303122
3123 phosphor::logging::log<phosphor::logging::level::WARNING>(
3124 "Restore to default will be performed on next BMC boot",
3125 phosphor::logging::entry("ACTION=0x%0X", cmd));
3126
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003127 break;
3128 }
3129 default:
3130 return ipmi::responseInvalidFieldRequest();
3131 }
3132
3133 constexpr uint8_t restorePending = 0;
3134 constexpr uint8_t restoreComplete = 1;
3135
3136 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3137 ? restorePending
3138 : restoreComplete;
3139 return ipmi::responseSuccess(restoreStatus);
3140}
3141
Chen Yugang39736d52019-07-12 16:24:33 +08003142ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3143{
3144 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003145 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003146
3147 try
3148 {
3149 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3150 std::string service =
3151 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
3152 Value variant =
3153 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3154 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
3155
3156 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3157 std::get<std::string>(variant)))
3158 {
3159 case nmi::NMISource::BMCSourceSignal::None:
3160 bmcSource = static_cast<uint8_t>(NmiSource::none);
3161 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003162 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3163 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003164 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003165 case nmi::NMISource::BMCSourceSignal::Watchdog:
3166 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003167 break;
3168 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3169 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3170 break;
3171 case nmi::NMISource::BMCSourceSignal::MemoryError:
3172 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3173 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003174 case nmi::NMISource::BMCSourceSignal::PciBusError:
3175 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003176 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003177 case nmi::NMISource::BMCSourceSignal::PCH:
3178 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003179 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003180 case nmi::NMISource::BMCSourceSignal::Chipset:
3181 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003182 break;
3183 default:
3184 phosphor::logging::log<phosphor::logging::level::ERR>(
3185 "NMI source: invalid property!",
3186 phosphor::logging::entry(
3187 "PROP=%s", std::get<std::string>(variant).c_str()));
3188 return ipmi::responseResponseError();
3189 }
3190 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -05003191 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003192 {
3193 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3194 return ipmi::responseResponseError();
3195 }
3196
3197 return ipmi::responseSuccess(bmcSource);
3198}
3199
3200ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3201{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003202 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003203
3204 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3205 nmi::NMISource::BMCSourceSignal::None;
3206
3207 switch (NmiSource(sourceId))
3208 {
3209 case NmiSource::none:
3210 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3211 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003212 case NmiSource::frontPanelButton:
3213 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003214 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003215 case NmiSource::watchdog:
3216 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003217 break;
3218 case NmiSource::chassisCmd:
3219 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3220 break;
3221 case NmiSource::memoryError:
3222 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3223 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003224 case NmiSource::pciBusError:
3225 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003226 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003227 case NmiSource::pch:
3228 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003229 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003230 case NmiSource::chipset:
3231 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003232 break;
3233 default:
3234 phosphor::logging::log<phosphor::logging::level::ERR>(
3235 "NMI source: invalid property!");
3236 return ipmi::responseResponseError();
3237 }
3238
3239 try
3240 {
3241 // keep NMI signal source
3242 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3243 std::string service =
3244 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003245 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3246 oemNmiBmcSourceObjPathProp,
3247 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003248 // set Enabled property to inform NMI source handling
3249 // to trigger a NMI_OUT BSOD.
3250 // if it's triggered by NMI source property changed,
3251 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3252 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3253 {
3254 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3255 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3256 static_cast<bool>(true));
3257 }
Chen Yugang39736d52019-07-12 16:24:33 +08003258 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003259 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003260 {
3261 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3262 return ipmi::responseResponseError();
3263 }
3264
3265 return ipmi::responseSuccess();
3266}
3267
James Feist63efafa2019-07-24 12:39:21 -07003268namespace dimmOffset
3269{
3270constexpr const char* dimmPower = "DimmPower";
3271constexpr const char* staticCltt = "StaticCltt";
3272constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3273constexpr const char* offsetInterface =
3274 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3275constexpr const char* property = "DimmOffset";
3276
3277}; // namespace dimmOffset
3278
3279ipmi::RspType<>
3280 ipmiOEMSetDimmOffset(uint8_t type,
3281 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3282{
3283 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3284 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3285 {
3286 return ipmi::responseInvalidFieldRequest();
3287 }
3288
3289 if (data.empty())
3290 {
3291 return ipmi::responseInvalidFieldRequest();
3292 }
3293 nlohmann::json json;
3294
3295 std::ifstream jsonStream(dimmOffsetFile);
3296 if (jsonStream.good())
3297 {
3298 json = nlohmann::json::parse(jsonStream, nullptr, false);
3299 if (json.is_discarded())
3300 {
3301 json = nlohmann::json();
3302 }
3303 jsonStream.close();
3304 }
3305
3306 std::string typeName;
3307 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3308 {
3309 typeName = dimmOffset::dimmPower;
3310 }
3311 else
3312 {
3313 typeName = dimmOffset::staticCltt;
3314 }
3315
3316 nlohmann::json& field = json[typeName];
3317
3318 for (const auto& [index, value] : data)
3319 {
3320 field[index] = value;
3321 }
3322
3323 for (nlohmann::json& val : field)
3324 {
3325 if (val == nullptr)
3326 {
3327 val = static_cast<uint8_t>(0);
3328 }
3329 }
3330
3331 std::ofstream output(dimmOffsetFile);
3332 if (!output.good())
3333 {
3334 std::cerr << "Error writing json file\n";
3335 return ipmi::responseResponseError();
3336 }
3337
3338 output << json.dump(4);
3339
3340 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3341 {
3342 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3343
Jason M. Bills0748c692022-09-08 15:34:08 -07003344 ipmi::DbusVariant offsets = field.get<std::vector<uint8_t>>();
James Feist63efafa2019-07-24 12:39:21 -07003345 auto call = bus->new_method_call(
3346 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3347 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3348 try
3349 {
3350 bus->call(call);
3351 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003352 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003353 {
3354 phosphor::logging::log<phosphor::logging::level::ERR>(
3355 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3356 phosphor::logging::entry("ERR=%s", e.what()));
3357 return ipmi::responseResponseError();
3358 }
3359 }
3360
3361 return ipmi::responseSuccess();
3362}
3363
3364ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3365{
3366
3367 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3368 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3369 {
3370 return ipmi::responseInvalidFieldRequest();
3371 }
3372
3373 std::ifstream jsonStream(dimmOffsetFile);
3374
3375 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3376 if (json.is_discarded())
3377 {
3378 std::cerr << "File error in " << dimmOffsetFile << "\n";
3379 return ipmi::responseResponseError();
3380 }
3381
3382 std::string typeName;
3383 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3384 {
3385 typeName = dimmOffset::dimmPower;
3386 }
3387 else
3388 {
3389 typeName = dimmOffset::staticCltt;
3390 }
3391
3392 auto it = json.find(typeName);
3393 if (it == json.end())
3394 {
3395 return ipmi::responseInvalidFieldRequest();
3396 }
3397
3398 if (it->size() <= index)
3399 {
3400 return ipmi::responseInvalidFieldRequest();
3401 }
3402
3403 uint8_t resp = it->at(index).get<uint8_t>();
3404 return ipmi::responseSuccess(resp);
3405}
3406
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003407namespace boot_options
3408{
3409
3410using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3411using IpmiValue = uint8_t;
3412constexpr auto ipmiDefault = 0;
3413
3414std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3415 {0x01, Source::Sources::Network},
3416 {0x02, Source::Sources::Disk},
3417 {0x05, Source::Sources::ExternalMedia},
3418 {0x0f, Source::Sources::RemovableMedia},
3419 {ipmiDefault, Source::Sources::Default}};
3420
3421std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003422 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003423
3424std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3425 {Source::Sources::Network, 0x01},
3426 {Source::Sources::Disk, 0x02},
3427 {Source::Sources::ExternalMedia, 0x05},
3428 {Source::Sources::RemovableMedia, 0x0f},
3429 {Source::Sources::Default, ipmiDefault}};
3430
3431std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003432 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003433
3434static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3435static constexpr auto bootSourceIntf =
3436 "xyz.openbmc_project.Control.Boot.Source";
3437static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3438static constexpr auto persistentObjPath =
3439 "/xyz/openbmc_project/control/host0/boot";
3440static constexpr auto oneTimePath =
3441 "/xyz/openbmc_project/control/host0/boot/one_time";
3442static constexpr auto bootSourceProp = "BootSource";
3443static constexpr auto bootModeProp = "BootMode";
3444static constexpr auto oneTimeBootEnableProp = "Enabled";
3445static constexpr auto httpBootMode =
3446 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3447
3448enum class BootOptionParameter : size_t
3449{
3450 setInProgress = 0x0,
3451 bootFlags = 0x5,
3452};
3453static constexpr uint8_t setComplete = 0x0;
3454static constexpr uint8_t setInProgress = 0x1;
3455static uint8_t transferStatus = setComplete;
3456static constexpr uint8_t setParmVersion = 0x01;
3457static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3458static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3459static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3460static constexpr uint8_t httpBoot = 0xd;
3461static constexpr uint8_t bootSourceMask = 0x3c;
3462
3463} // namespace boot_options
3464
3465ipmi::RspType<uint8_t, // version
3466 uint8_t, // param
3467 uint8_t, // data0, dependent on parameter
3468 std::optional<uint8_t> // data1, dependent on parameter
3469 >
3470 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3471{
3472 using namespace boot_options;
3473 uint8_t bootOption = 0;
3474
3475 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3476 {
3477 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3478 std::nullopt);
3479 }
3480
3481 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3482 {
3483 phosphor::logging::log<phosphor::logging::level::ERR>(
3484 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003485 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003486 }
3487
3488 try
3489 {
3490 auto oneTimeEnabled = false;
3491 // read one time Enabled property
3492 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3493 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3494 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3495 enabledIntf, oneTimeBootEnableProp);
3496 oneTimeEnabled = std::get<bool>(variant);
3497
3498 // get BootSource and BootMode properties
3499 // according to oneTimeEnable
3500 auto bootObjPath = oneTimePath;
3501 if (oneTimeEnabled == false)
3502 {
3503 bootObjPath = persistentObjPath;
3504 }
3505
3506 service = getService(*dbus, bootModeIntf, bootObjPath);
3507 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3508 bootModeProp);
3509
3510 auto bootMode =
3511 Mode::convertModesFromString(std::get<std::string>(variant));
3512
3513 service = getService(*dbus, bootSourceIntf, bootObjPath);
3514 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3515 bootSourceProp);
3516
3517 if (std::get<std::string>(variant) == httpBootMode)
3518 {
3519 bootOption = httpBoot;
3520 }
3521 else
3522 {
3523 auto bootSource = Source::convertSourcesFromString(
3524 std::get<std::string>(variant));
3525 bootOption = sourceDbusToIpmi.at(bootSource);
3526 if (Source::Sources::Default == bootSource)
3527 {
3528 bootOption = modeDbusToIpmi.at(bootMode);
3529 }
3530 }
3531
3532 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3533 : setParmBootFlagsValidPermanent;
3534 bootOption <<= 2; // shift for responseconstexpr
3535 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3536 bootOption);
3537 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003538 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003539 {
3540 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3541 return ipmi::responseResponseError();
3542 }
3543}
3544
3545ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3546 std::optional<uint8_t> bootOption)
3547{
3548 using namespace boot_options;
3549 auto oneTimeEnabled = false;
3550
Mike Jonesbc01d212022-06-16 12:41:33 -07003551 if (bootFlag == 0 && bootParam == 0)
3552 {
3553 phosphor::logging::log<phosphor::logging::level::ERR>(
3554 "Unsupported parameter");
3555 return ipmi::response(ccParameterNotSupported);
3556 }
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003557 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3558 {
3559 if (bootOption)
3560 {
3561 return ipmi::responseReqDataLenInvalid();
3562 }
3563
3564 if (transferStatus == setInProgress)
3565 {
3566 phosphor::logging::log<phosphor::logging::level::ERR>(
3567 "boot option set in progress!");
3568 return ipmi::responseResponseError();
3569 }
3570
3571 transferStatus = bootParam;
3572 return ipmi::responseSuccess();
3573 }
3574
3575 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3576 {
3577 phosphor::logging::log<phosphor::logging::level::ERR>(
3578 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003579 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003580 }
3581
3582 if (!bootOption)
3583 {
3584 return ipmi::responseReqDataLenInvalid();
3585 }
3586
3587 if (((bootOption.value() & bootSourceMask) >> 2) !=
3588 httpBoot) // not http boot, exit
3589 {
3590 phosphor::logging::log<phosphor::logging::level::ERR>(
3591 "wrong boot option parameter!");
3592 return ipmi::responseParmOutOfRange();
3593 }
3594
3595 try
3596 {
3597 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3598 setParmBootFlagsPermanent;
3599
3600 // read one time Enabled property
3601 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3602 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3603 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3604 enabledIntf, oneTimeBootEnableProp);
3605 oneTimeEnabled = std::get<bool>(variant);
3606
3607 /*
3608 * Check if the current boot setting is onetime or permanent, if the
3609 * request in the command is otherwise, then set the "Enabled"
3610 * property in one_time object path to 'True' to indicate onetime
3611 * and 'False' to indicate permanent.
3612 *
3613 * Once the onetime/permanent setting is applied, then the bootMode
3614 * and bootSource is updated for the corresponding object.
3615 */
3616 if (permanent == oneTimeEnabled)
3617 {
3618 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3619 oneTimeBootEnableProp, !permanent);
3620 }
3621
3622 // set BootSource and BootMode properties
3623 // according to oneTimeEnable or persistent
3624 auto bootObjPath = oneTimePath;
3625 if (oneTimeEnabled == false)
3626 {
3627 bootObjPath = persistentObjPath;
3628 }
3629 std::string bootMode =
3630 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3631 std::string bootSource = httpBootMode;
3632
3633 service = getService(*dbus, bootModeIntf, bootObjPath);
3634 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3635 bootMode);
3636
3637 service = getService(*dbus, bootSourceIntf, bootObjPath);
3638 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3639 bootSourceProp, bootSource);
3640 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003641 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003642 {
3643 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3644 return ipmi::responseResponseError();
3645 }
3646
3647 return ipmi::responseSuccess();
3648}
3649
Jason M. Bills0748c692022-09-08 15:34:08 -07003650using BasicVariantType = ipmi::DbusVariant;
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003651using PropertyMapType =
3652 boost::container::flat_map<std::string, BasicVariantType>;
3653static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3654 "xyz.openbmc_project.Configuration.PSUPresence"};
3655int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3656 std::vector<uint64_t>& addrTable)
3657{
3658 boost::system::error_code ec;
3659 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3660 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3661 "/xyz/openbmc_project/object_mapper",
3662 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3663 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3664 if (ec)
3665 {
3666 phosphor::logging::log<phosphor::logging::level::ERR>(
3667 "Failed to set dbus property to cold redundancy");
3668 return -1;
3669 }
3670 for (const auto& object : subtree)
3671 {
3672 std::string pathName = object.first;
3673 for (const auto& serviceIface : object.second)
3674 {
3675 std::string serviceName = serviceIface.first;
3676
3677 ec.clear();
3678 PropertyMapType propMap =
3679 ctx->bus->yield_method_call<PropertyMapType>(
3680 ctx->yield, ec, serviceName, pathName,
3681 "org.freedesktop.DBus.Properties", "GetAll",
3682 "xyz.openbmc_project.Configuration.PSUPresence");
3683 if (ec)
3684 {
3685 phosphor::logging::log<phosphor::logging::level::ERR>(
3686 "Failed to set dbus property to cold redundancy");
3687 return -1;
3688 }
3689 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3690 auto psuAddress =
3691 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3692
3693 if (psuBus == nullptr || psuAddress == nullptr)
3694 {
3695 std::cerr << "error finding necessary "
3696 "entry in configuration\n";
3697 return -1;
3698 }
3699 bus = static_cast<uint8_t>(*psuBus);
3700 addrTable = *psuAddress;
3701 return 0;
3702 }
3703 }
3704 return -1;
3705}
3706
3707static const constexpr uint8_t addrOffset = 8;
3708static const constexpr uint8_t psuRevision = 0xd9;
3709static const constexpr uint8_t defaultPSUBus = 7;
3710// Second Minor, Primary Minor, Major
3711static const constexpr size_t verLen = 3;
3712ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3713{
3714 uint8_t bus = defaultPSUBus;
3715 std::vector<uint64_t> addrTable;
3716 std::vector<uint8_t> result;
3717 if (getPSUAddress(ctx, bus, addrTable))
3718 {
3719 std::cerr << "Failed to get PSU bus and address\n";
3720 return ipmi::responseResponseError();
3721 }
3722
3723 for (const auto& slaveAddr : addrTable)
3724 {
3725 std::vector<uint8_t> writeData = {psuRevision};
3726 std::vector<uint8_t> readBuf(verLen);
3727 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3728 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3729
3730 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3731 if (retI2C != ipmi::ccSuccess)
3732 {
3733 for (size_t idx = 0; idx < verLen; idx++)
3734 {
3735 result.emplace_back(0x00);
3736 }
3737 }
3738 else
3739 {
3740 for (const uint8_t& data : readBuf)
3741 {
3742 result.emplace_back(data);
3743 }
3744 }
3745 }
3746
3747 return ipmi::responseSuccess(result);
3748}
3749
srikanta mondal2030d7c2020-05-03 17:25:25 +00003750std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3751 const std::string& name)
3752{
3753 Value dbusValue = 0;
3754 std::string serviceName;
3755
3756 boost::system::error_code ec =
3757 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3758
3759 if (ec)
3760 {
3761 phosphor::logging::log<phosphor::logging::level::ERR>(
3762 "Failed to perform Multinode getService.");
3763 return std::nullopt;
3764 }
3765
3766 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3767 multiNodeIntf, name, dbusValue);
3768 if (ec)
3769 {
3770 phosphor::logging::log<phosphor::logging::level::ERR>(
3771 "Failed to perform Multinode get property");
3772 return std::nullopt;
3773 }
3774
3775 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3776 if (!multiNodeVal)
3777 {
3778 phosphor::logging::log<phosphor::logging::level::ERR>(
3779 "getMultiNodeInfoPresence: error to get multinode");
3780 return std::nullopt;
3781 }
3782 return *multiNodeVal;
3783}
3784
3785/** @brief implements OEM get reading command
3786 * @param domain ID
3787 * @param reading Type
3788 * - 00h = platform Power Consumption
3789 * - 01h = inlet Air Temp
3790 * - 02h = icc_TDC from PECI
3791 * @param reserved, write as 0000h
3792 *
3793 * @returns IPMI completion code plus response data
3794 * - response
3795 * - domain ID
3796 * - reading Type
3797 * - 00h = platform Power Consumption
3798 * - 01h = inlet Air Temp
3799 * - 02h = icc_TDC from PECI
3800 * - reading
3801 */
3802ipmi::RspType<uint4_t, // domain ID
3803 uint4_t, // reading Type
3804 uint16_t // reading Value
3805 >
3806 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3807 uint4_t readingType, uint16_t reserved)
3808{
3809 constexpr uint8_t platformPower = 0;
3810 constexpr uint8_t inletAirTemp = 1;
3811 constexpr uint8_t iccTdc = 2;
3812
3813 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3814 {
3815 return ipmi::responseInvalidFieldRequest();
3816 }
3817
3818 // This command should run only from multi-node product.
3819 // For all other platforms this command will return invalid.
3820
3821 std::optional<uint8_t> nodeInfo =
3822 getMultiNodeInfoPresence(ctx, "NodePresence");
3823 if (!nodeInfo || !*nodeInfo)
3824 {
3825 return ipmi::responseInvalidCommand();
3826 }
3827
3828 uint16_t oemReadingValue = 0;
3829 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3830 {
3831 double value = 0;
3832 boost::system::error_code ec = ipmi::getDbusProperty(
3833 ctx, "xyz.openbmc_project.HwmonTempSensor",
3834 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3835 "xyz.openbmc_project.Sensor.Value", "Value", value);
3836 if (ec)
3837 {
3838 phosphor::logging::log<phosphor::logging::level::ERR>(
3839 "Failed to get BMC Get OEM temperature",
3840 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3841 return ipmi::responseUnspecifiedError();
3842 }
3843 // Take the Inlet temperature
3844 oemReadingValue = static_cast<uint16_t>(value);
3845 }
3846 else
3847 {
3848 phosphor::logging::log<phosphor::logging::level::ERR>(
3849 "Currently Get OEM Reading support only for Inlet Air Temp");
3850 return ipmi::responseParmOutOfRange();
3851 }
3852 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3853}
3854
AppaRao Puli28972062019-11-11 02:04:45 +05303855/** @brief implements the maximum size of
3856 * bridgeable messages used between KCS and
3857 * IPMB interfacesget security mode command.
3858 *
3859 * @returns IPMI completion code with following data
3860 * - KCS Buffer Size (In multiples of four bytes)
3861 * - IPMB Buffer Size (In multiples of four bytes)
3862 **/
3863ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3864{
3865 // for now this is hard coded; really this number is dependent on
3866 // the BMC kcs driver as well as the host kcs driver....
3867 // we can't know the latter.
3868 uint8_t kcsMaxBufferSize = 63 / 4;
3869 uint8_t ipmbMaxBufferSize = 128 / 4;
3870
3871 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3872}
3873
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003874ipmi::RspType<std::vector<uint8_t>>
3875 ipmiOEMReadPFRMailbox(ipmi::Context::ptr& ctx, const uint8_t readRegister,
3876 const uint8_t numOfBytes, uint8_t registerIdentifier)
3877{
3878 if (!ipmi::mailbox::i2cConfigLoaded)
3879 {
3880
3881 phosphor::logging::log<phosphor::logging::level::ERR>(
3882 "Calling PFR Load Configuration Function to Get I2C Bus and Slave "
3883 "Address ");
3884
3885 ipmi::mailbox::loadPfrConfig(ctx, ipmi::mailbox::i2cConfigLoaded);
3886 }
3887
3888 if (!numOfBytes && !readRegister)
3889 {
3890 phosphor::logging::log<phosphor::logging::level::ERR>(
3891 "OEM IPMI command: Read & write count are 0 which is invalid ");
3892 return ipmi::responseInvalidFieldRequest();
3893 }
3894
3895 switch (registerIdentifier)
3896 {
3897 case ipmi::mailbox::registerType::fifoReadRegister:
3898 {
3899 // Check if readRegister is an FIFO read register
3900 if (registerIdentifier == 1)
3901 {
3902 if (ipmi::mailbox::readFifoReg.find(readRegister) ==
3903 ipmi::mailbox::readFifoReg.end())
3904 {
3905 phosphor::logging::log<phosphor::logging::level::ERR>(
3906 "OEM IPMI command: Register is not a Read FIFO ");
3907 return ipmi::responseInvalidFieldRequest();
3908 }
3909
3910 phosphor::logging::log<phosphor::logging::level::ERR>(
3911 "OEM IPMI command: Register is a Read FIFO ");
3912
3913 ipmi::mailbox::writefifo(ipmi::mailbox::provisioningCommand,
3914 readRegister);
3915 ipmi::mailbox::writefifo(ipmi::mailbox::triggerCommand,
3916 ipmi::mailbox::flushRead);
3917
3918 std::vector<uint8_t> writeData = {ipmi::mailbox::readFifo};
3919 std::vector<uint8_t> readBuf(1);
3920 std::vector<uint8_t> result;
3921
3922 for (int i = 0; i < numOfBytes; i++)
3923 {
3924
3925 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
3926 ipmi::mailbox::slaveAddr,
3927 writeData, readBuf);
3928 if (ret != ipmi::ccSuccess)
3929 {
3930 return ipmi::response(ret);
3931 }
3932
3933 else
3934 {
3935 for (const uint8_t& data : readBuf)
3936 {
3937 result.emplace_back(data);
3938 }
3939 }
3940 }
3941
3942 return ipmi::responseSuccess(result);
3943 }
3944 }
3945
3946 case ipmi::mailbox::registerType::singleByteRegister:
3947 {
3948 phosphor::logging::log<phosphor::logging::level::ERR>(
3949 "OEM IPMI command: Register is a Single Byte Register ");
3950
3951 std::vector<uint8_t> writeData = {readRegister};
3952 std::vector<uint8_t> readBuf(numOfBytes);
3953
3954 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
3955 ipmi::mailbox::slaveAddr,
3956 writeData, readBuf);
3957 if (ret != ipmi::ccSuccess)
3958 {
3959 return ipmi::response(ret);
3960 }
3961 return ipmi::responseSuccess(readBuf);
3962 }
3963
3964 default:
3965 {
3966
3967 phosphor::logging::log<phosphor::logging::level::ERR>(
3968 "OEM IPMI command: Register identifier is not valid.It should "
3969 "be 0 "
3970 "for Single Byte Register and 1 for FIFO Read Register");
3971
3972 return ipmi::responseInvalidFieldRequest();
3973 }
3974 }
3975}
3976
Jason M. Bills64796042018-10-03 16:51:55 -07003977static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003978{
3979 phosphor::logging::log<phosphor::logging::level::INFO>(
3980 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003981 ipmiPrintAndRegister(intel::netFnGeneral,
3982 intel::general::cmdGetChassisIdentifier, NULL,
3983 ipmiOEMGetChassisIdentifier,
3984 PRIVILEGE_USER); // get chassis identifier
3985
3986 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3987 NULL, ipmiOEMSetSystemGUID,
3988 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003989
3990 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003991 registerHandler(prioOemBase, intel::netFnGeneral,
3992 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3993 ipmiOEMDisableBMCSystemReset);
3994
Jason M. Billsb02bf092019-08-15 13:01:56 -07003995 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003996 registerHandler(prioOemBase, intel::netFnGeneral,
3997 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3998 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003999
Vernon Mauery98bbf692019-09-16 11:14:59 -07004000 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
4001 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004002
Chen Yugang7a04f3a2019-10-08 11:12:35 +08004003 registerHandler(prioOemBase, intel::netFnGeneral,
4004 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
4005 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004006
Vernon Mauery98bbf692019-09-16 11:14:59 -07004007 ipmiPrintAndRegister(intel::netFnGeneral,
4008 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
4009 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304010
Vernon Mauery98bbf692019-09-16 11:14:59 -07004011 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4012 intel::general::cmdSendEmbeddedFWUpdStatus,
4013 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304014
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05304015 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
4016 Privilege::Admin, ipmiOEMSlotIpmb);
4017
Vernon Mauery98bbf692019-09-16 11:14:59 -07004018 ipmiPrintAndRegister(intel::netFnGeneral,
4019 intel::general::cmdSetPowerRestoreDelay, NULL,
4020 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
4021
4022 ipmiPrintAndRegister(intel::netFnGeneral,
4023 intel::general::cmdGetPowerRestoreDelay, NULL,
4024 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
4025
4026 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4027 intel::general::cmdSetOEMUser2Activation,
4028 Privilege::Callback, ipmiOEMSetUser2Activation);
4029
4030 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4031 intel::general::cmdSetSpecialUserPassword,
4032 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05304033
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004034 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004035 registerHandler(prioOemBase, intel::netFnGeneral,
4036 intel::general::cmdGetProcessorErrConfig, Privilege::User,
4037 ipmiOEMGetProcessorErrConfig);
4038
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004039 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004040 registerHandler(prioOemBase, intel::netFnGeneral,
4041 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
4042 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004043
Vernon Mauery98bbf692019-09-16 11:14:59 -07004044 ipmiPrintAndRegister(intel::netFnGeneral,
4045 intel::general::cmdSetShutdownPolicy, NULL,
4046 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004047
Vernon Mauery98bbf692019-09-16 11:14:59 -07004048 ipmiPrintAndRegister(intel::netFnGeneral,
4049 intel::general::cmdGetShutdownPolicy, NULL,
4050 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004051
anil kumar appanaf945eee2019-09-25 23:29:11 +00004052 registerHandler(prioOemBase, intel::netFnGeneral,
4053 intel::general::cmdSetFanConfig, Privilege::User,
4054 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08004055
Vernon Mauery98bbf692019-09-16 11:14:59 -07004056 registerHandler(prioOemBase, intel::netFnGeneral,
4057 intel::general::cmdGetFanConfig, Privilege::User,
4058 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07004059
Vernon Mauery98bbf692019-09-16 11:14:59 -07004060 registerHandler(prioOemBase, intel::netFnGeneral,
4061 intel::general::cmdGetFanSpeedOffset, Privilege::User,
4062 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004063
Vernon Mauery98bbf692019-09-16 11:14:59 -07004064 registerHandler(prioOemBase, intel::netFnGeneral,
4065 intel::general::cmdSetFanSpeedOffset, Privilege::User,
4066 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004067
Vernon Mauery98bbf692019-09-16 11:14:59 -07004068 registerHandler(prioOemBase, intel::netFnGeneral,
4069 intel::general::cmdSetFscParameter, Privilege::User,
4070 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07004071
Vernon Mauery98bbf692019-09-16 11:14:59 -07004072 registerHandler(prioOemBase, intel::netFnGeneral,
4073 intel::general::cmdGetFscParameter, Privilege::User,
4074 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05304075
Vernon Mauery98bbf692019-09-16 11:14:59 -07004076 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4077 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
4078 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08004079
Vernon Mauery98bbf692019-09-16 11:14:59 -07004080 registerHandler(prioOemBase, intel::netFnGeneral,
4081 intel::general::cmdGetNmiStatus, Privilege::User,
4082 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08004083
Vernon Mauery98bbf692019-09-16 11:14:59 -07004084 registerHandler(prioOemBase, intel::netFnGeneral,
4085 intel::general::cmdSetNmiStatus, Privilege::Operator,
4086 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004087
Vernon Mauery98bbf692019-09-16 11:14:59 -07004088 registerHandler(prioOemBase, intel::netFnGeneral,
4089 intel::general::cmdGetEfiBootOptions, Privilege::User,
4090 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004091
Vernon Mauery98bbf692019-09-16 11:14:59 -07004092 registerHandler(prioOemBase, intel::netFnGeneral,
4093 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
4094 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304095
Vernon Mauery98bbf692019-09-16 11:14:59 -07004096 registerHandler(prioOemBase, intel::netFnGeneral,
4097 intel::general::cmdGetSecurityMode, Privilege::User,
4098 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304099
Vernon Mauery98bbf692019-09-16 11:14:59 -07004100 registerHandler(prioOemBase, intel::netFnGeneral,
4101 intel::general::cmdSetSecurityMode, Privilege::Admin,
4102 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004103
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00004104 registerHandler(prioOemBase, intel::netFnGeneral,
4105 intel::general::cmdGetLEDStatus, Privilege::Admin,
4106 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08004107
Vernon Mauery98bbf692019-09-16 11:14:59 -07004108 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
4109 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
4110 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
4111
4112 registerHandler(prioOemBase, intel::netFnGeneral,
4113 intel::general::cmdSetFaultIndication, Privilege::Operator,
4114 ipmiOEMSetFaultIndication);
4115
4116 registerHandler(prioOemBase, intel::netFnGeneral,
4117 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
4118 ipmiOEMSetCRConfig);
4119
4120 registerHandler(prioOemBase, intel::netFnGeneral,
4121 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
4122 ipmiOEMGetCRConfig);
4123
4124 registerHandler(prioOemBase, intel::netFnGeneral,
4125 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004126 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07004127
Vernon Mauery98bbf692019-09-16 11:14:59 -07004128 registerHandler(prioOemBase, intel::netFnGeneral,
4129 intel::general::cmdSetDimmOffset, Privilege::Operator,
4130 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07004131
Vernon Mauery98bbf692019-09-16 11:14:59 -07004132 registerHandler(prioOemBase, intel::netFnGeneral,
4133 intel::general::cmdGetDimmOffset, Privilege::Operator,
4134 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08004135
Cheng C Yang4e6ee152019-09-25 10:27:44 +08004136 registerHandler(prioOemBase, intel::netFnGeneral,
4137 intel::general::cmdGetPSUVersion, Privilege::User,
4138 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05304139
4140 registerHandler(prioOemBase, intel::netFnGeneral,
4141 intel::general::cmdGetBufferSize, Privilege::User,
4142 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00004143
4144 registerHandler(prioOemBase, intel::netFnGeneral,
4145 intel::general::cmdOEMGetReading, Privilege::User,
4146 ipmiOEMGetReading);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00004147
4148 registerHandler(prioOemBase, intel::netFnApp, intel::app::cmdPFRMailboxRead,
4149 Privilege::Admin, ipmiOEMReadPFRMailbox);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004150}
4151
4152} // namespace ipmi