blob: 21ba22d21444b09007ff91762dc04f3eae4909de [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>
47#include <iostream>
48#include <regex>
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +000049#include <set>
James Feistfcd2d3a2020-05-28 10:38:15 -070050#include <string>
51#include <variant>
52#include <vector>
53
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080054namespace ipmi
55{
Jason M. Bills64796042018-10-03 16:51:55 -070056static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070057
Jason M. Bills64796042018-10-03 16:51:55 -070058static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080059
Suryakanth Sekard509eb92018-11-15 17:44:11 +053060static constexpr auto ethernetIntf =
61 "xyz.openbmc_project.Network.EthernetInterface";
62static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
63static constexpr auto networkService = "xyz.openbmc_project.Network";
64static constexpr auto networkRoot = "/xyz/openbmc_project/network";
65
Chen Yugang97cf96e2019-11-01 08:55:11 +080066static constexpr const char* oemNmiSourceIntf =
67 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080068static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080069 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080070static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
71static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
72
James Feist63efafa2019-07-24 12:39:21 -070073static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
srikanta mondal2030d7c2020-05-03 17:25:25 +000074static constexpr const char* multiNodeObjPath =
75 "/xyz/openbmc_project/MultiNode/Status";
76static constexpr const char* multiNodeIntf =
77 "xyz.openbmc_project.Chassis.MultiNode";
James Feist63efafa2019-07-24 12:39:21 -070078
Chen Yugang39736d52019-07-12 16:24:33 +080079enum class NmiSource : uint8_t
80{
81 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080082 frontPanelButton = 1,
83 watchdog = 2,
84 chassisCmd = 3,
85 memoryError = 4,
86 pciBusError = 5,
87 pch = 6,
88 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080089};
90
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053091enum class SpecialUserIndex : uint8_t
92{
93 rootUser = 0,
94 atScaleDebugUser = 1
95};
96
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053097static constexpr const char* restricionModeService =
98 "xyz.openbmc_project.RestrictionMode.Manager";
99static constexpr const char* restricionModeBasePath =
100 "/xyz/openbmc_project/control/security/restriction_mode";
101static constexpr const char* restricionModeIntf =
102 "xyz.openbmc_project.Control.Security.RestrictionMode";
103static constexpr const char* restricionModeProperty = "RestrictionMode";
104
105static constexpr const char* specialModeService =
106 "xyz.openbmc_project.SpecialMode";
107static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530108 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530109static constexpr const char* specialModeIntf =
110 "xyz.openbmc_project.Security.SpecialMode";
111static constexpr const char* specialModeProperty = "SpecialMode";
112
113static constexpr const char* dBusPropertyIntf =
114 "org.freedesktop.DBus.Properties";
115static constexpr const char* dBusPropertyGetMethod = "Get";
116static constexpr const char* dBusPropertySetMethod = "Set";
117
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800118// return code: 0 successful
119int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
120{
121 std::string objpath = "/xyz/openbmc_project/FruDevice";
122 std::string intf = "xyz.openbmc_project.FruDeviceManager";
123 std::string service = getService(bus, intf, objpath);
124 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
125 if (valueTree.empty())
126 {
127 phosphor::logging::log<phosphor::logging::level::ERR>(
128 "No object implements interface",
129 phosphor::logging::entry("INTF=%s", intf.c_str()));
130 return -1;
131 }
132
Jason M. Bills64796042018-10-03 16:51:55 -0700133 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800134 {
135 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
136 if (interface == item.second.end())
137 {
138 continue;
139 }
140
141 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
142 if (property == interface->second.end())
143 {
144 continue;
145 }
146
147 try
148 {
149 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700150 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700151 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800152 {
153 phosphor::logging::log<phosphor::logging::level::ERR>(
154 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800155 return -1;
156 }
Jason M. Bills64796042018-10-03 16:51:55 -0700157 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800158 return 0;
159 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500160 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800161 {
Jason M. Bills64796042018-10-03 16:51:55 -0700162 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800163 return -1;
164 }
165 }
166 return -1;
167}
Jason M. Bills64796042018-10-03 16:51:55 -0700168
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +0000169namespace mailbox
170{
171static uint8_t bus = 4;
172static std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
173static uint8_t slaveAddr = 56;
174static constexpr auto systemRoot = "/xyz/openbmc_project/inventory/system";
175static constexpr auto sessionIntf = "xyz.openbmc_project.Configuration.PFR";
176const std::string match = "Baseboard/PFR";
177static bool i2cConfigLoaded = false;
178// Command register for UFM provisioning/access commands; read/write allowed
179// from CPU/BMC.
180static const constexpr uint8_t provisioningCommand = 0x0b;
181// Trigger register for the command set in the previous offset.
182static const constexpr uint8_t triggerCommand = 0x0c;
183// Set 0x0c to 0x05 to execute command specified at “UFM/Provisioning Command”
184// register
185static const constexpr uint8_t flushRead = 0x05;
186// FIFO read registers
187std::set<uint8_t> readFifoReg = {0x08, 0x0C, 0x0D, 0x13};
188
189// UFM Read FIFO
190static const constexpr uint8_t readFifo = 0x0e;
191
192enum registerType : uint8_t
193{
194 singleByteRegister = 0,
195 fifoReadRegister,
196
197};
198
199void loadPfrConfig(ipmi::Context::ptr& ctx, bool& i2cConfigLoaded)
200{
201 ipmi::ObjectTree objectTree;
202
203 boost::system::error_code ec = ipmi::getAllDbusObjects(
204 ctx, systemRoot, sessionIntf, match, objectTree);
205
206 if (ec)
207 {
208
209 phosphor::logging::log<phosphor::logging::level::ERR>(
210 "Failed to fetch PFR object from dbus",
211 phosphor::logging::entry("INTERFACE=%s", sessionIntf),
212 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
213
214 return;
215 }
216
217 for (auto& softObject : objectTree)
218 {
219 const std::string& objPath = softObject.first;
220 const std::string& serviceName = softObject.second.begin()->first;
221 // PFR object found.. check for PFR support
222 ipmi::PropertyMap result;
223
224 ec = ipmi::getAllDbusProperties(ctx, serviceName, objPath, sessionIntf,
225 result);
226
227 if (ec)
228 {
229 phosphor::logging::log<phosphor::logging::level::ERR>(
230 "Failed to fetch pfr properties",
231 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
232 return;
233 }
234
235 const uint64_t* i2cBusNum = nullptr;
236 const uint64_t* address = nullptr;
237
238 for (const auto& [propName, propVariant] : result)
239 {
240
241 if (propName == "Address")
242 {
243 address = std::get_if<uint64_t>(&propVariant);
244 }
245 else if (propName == "Bus")
246 {
247 i2cBusNum = std::get_if<uint64_t>(&propVariant);
248 }
249 }
250
251 if ((address == nullptr) || (i2cBusNum == nullptr))
252 {
253 phosphor::logging::log<phosphor::logging::level::ERR>(
254 "Unable to read the pfr properties");
255 return;
256 }
257
258 bus = static_cast<int>(*i2cBusNum);
259 i2cBus = "/dev/i2c-" + std::to_string(bus);
260 slaveAddr = static_cast<int>(*address);
261
262 i2cConfigLoaded = true;
263 }
264}
265
266void writefifo(const uint8_t cmdReg, const uint8_t val)
267{
268 // Based on the spec, writing cmdReg to address val on this device, will
269 // trigger the write FIFO operation.
270 std::vector<uint8_t> writeData = {cmdReg, val};
271 std::vector<uint8_t> readBuf(0);
272 ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf);
273}
274
275} // namespace mailbox
276
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800277// Returns the Chassis Identifier (serial #)
278ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
279 ipmi_request_t request,
280 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700281 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800282 ipmi_context_t context)
283{
284 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700285 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800286 {
Jason M. Bills64796042018-10-03 16:51:55 -0700287 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800288 return IPMI_CC_REQ_DATA_LEN_INVALID;
289 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700290 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
291 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800292 {
Jason M. Bills64796042018-10-03 16:51:55 -0700293 *dataLen = serial.size(); // length will never exceed response length
294 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800295 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700296 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297 return IPMI_CC_OK;
298 }
Jason M. Bills64796042018-10-03 16:51:55 -0700299 *dataLen = 0;
300 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800301}
302
303ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
304 ipmi_request_t request,
305 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700306 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307{
308 static constexpr size_t safeBufferLength = 50;
309 char buf[safeBufferLength] = {0};
310 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
311
Jason M. Bills64796042018-10-03 16:51:55 -0700312 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800313 {
Jason M. Bills64796042018-10-03 16:51:55 -0700314 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 return IPMI_CC_REQ_DATA_LEN_INVALID;
316 }
317
Jason M. Bills64796042018-10-03 16:51:55 -0700318 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800319
320 snprintf(
321 buf, safeBufferLength,
322 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
323 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
324 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
325 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
326 Data->node3, Data->node2, Data->node1);
327 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
328 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800329
330 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
331 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700332 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
333 std::string service = getService(*dbus, intf, objpath);
334 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800335 return IPMI_CC_OK;
336}
337
Jason M. Billsb02bf092019-08-15 13:01:56 -0700338ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
339 uint7_t reserved1)
340{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000341 if (reserved1)
342 {
343 return ipmi::responseInvalidFieldRequest();
344 }
345
Jason M. Billsb02bf092019-08-15 13:01:56 -0700346 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
347
348 try
349 {
350 auto service =
351 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
352 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
353 bmcResetDisablesIntf, "ResetOnSMI",
354 !disableResetOnSMI);
355 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500356 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700357 {
358 phosphor::logging::log<phosphor::logging::level::ERR>(
359 "Failed to set BMC reset disables",
360 phosphor::logging::entry("EXCEPTION=%s", e.what()));
361 return ipmi::responseUnspecifiedError();
362 }
363
364 return ipmi::responseSuccess();
365}
366
367ipmi::RspType<bool, // disableResetOnSMI
368 uint7_t // reserved
369 >
370 ipmiOEMGetBMCResetDisables()
371{
372 bool disableResetOnSMI = true;
373
374 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
375 try
376 {
377 auto service =
378 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
379 Value variant =
380 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
381 bmcResetDisablesIntf, "ResetOnSMI");
382 disableResetOnSMI = !std::get<bool>(variant);
383 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500384 catch (const std::exception& e)
Jason M. Billsb02bf092019-08-15 13:01:56 -0700385 {
386 phosphor::logging::log<phosphor::logging::level::ERR>(
387 "Failed to get BMC reset disables",
388 phosphor::logging::entry("EXCEPTION=%s", e.what()));
389 return ipmi::responseUnspecifiedError();
390 }
391
392 return ipmi::responseSuccess(disableResetOnSMI, 0);
393}
394
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800395ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
396 ipmi_request_t request, ipmi_response_t response,
397 ipmi_data_len_t dataLen, ipmi_context_t context)
398{
399 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
400
Jason M. Bills64796042018-10-03 16:51:55 -0700401 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800402 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800403 *dataLen = 0;
404 return IPMI_CC_REQ_DATA_LEN_INVALID;
405 }
Jason M. Bills64796042018-10-03 16:51:55 -0700406 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000407 for (auto idChar : idString)
408 {
409 if (!std::isprint(static_cast<unsigned char>(idChar)))
410 {
411 phosphor::logging::log<phosphor::logging::level::ERR>(
412 "BIOS ID contains non printable character");
413 return IPMI_CC_INVALID_FIELD_REQUEST;
414 }
415 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800416
Vernon Mauery15419dd2019-05-24 09:40:30 -0700417 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000418 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
419 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800420 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800421 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
422 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700423 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800424 *dataLen = 1;
425 return IPMI_CC_OK;
426}
427
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000428bool getActiveHSCSoftwareVersionInfo(std::string& hscVersion, size_t hscNumber)
429{
430 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
431 try
432 {
433 std::string hsbpObjPath =
434 "/xyz/openbmc_project/software/HSBP_" + std::to_string(hscNumber);
435 auto service = getService(*dbus, biosVersionIntf, hsbpObjPath);
436 Value hscVersionValue =
437 getDbusProperty(*dbus, "xyz.openbmc_project.HsbpManager",
438 hsbpObjPath, biosVersionIntf, "Version");
439 hscVersion = std::get<std::string>(hscVersionValue);
440 }
441 catch (const sdbusplus::exception::exception& e)
442 {
443 phosphor::logging::log<phosphor::logging::level::INFO>(
444 "Failed to retrieve HSBP version information",
445 phosphor::logging::entry("HSBP Number=%d", hscNumber));
446 return false;
447 }
448 return true;
449}
450
451bool getHscVerInfo(ipmi::Context::ptr ctx, uint8_t& hsc0Major,
452 uint8_t& hsc0Minor, uint8_t& hsc1Major, uint8_t& hsc1Minor,
453 uint8_t& hsc2Major, uint8_t& hsc2Minor)
454{
455 std::string hscVersion;
456 std::array<uint8_t, 6> hscVersions{0};
457
458 for (size_t hscNumber = 1; hscNumber <= 3; hscNumber++)
459 {
460 if (!getActiveHSCSoftwareVersionInfo(hscVersion, hscNumber))
461 {
462 continue;
463 }
464 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?)");
465 constexpr size_t matchedPhosphor = 4;
466 std::smatch results;
467 // hscVersion = BOOT_VER.FPGA_VER.SECURITY_REVISION (Example: 00.02.01)
468 if (std::regex_match(hscVersion, results, pattern1))
469 {
470 // Major version is FPGA_VER and Minor version is SECURITY_REV
471 if (results.size() == matchedPhosphor)
472 {
473 int index = (hscNumber - 1) * 2;
474 hscVersions[index] =
475 static_cast<uint8_t>(std::stoi(results[2]));
476 hscVersions[index + 1] =
477 static_cast<uint8_t>(std::stoi(results[3]));
478 }
479 }
480 }
481 hsc0Major = hscVersions[0];
482 hsc0Minor = hscVersions[1];
483 hsc1Major = hscVersions[2];
484 hsc1Minor = hscVersions[3];
485 hsc2Major = hscVersions[4];
486 hsc2Minor = hscVersions[5];
487 return true;
488}
489
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530490bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
491 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800492{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800493 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530494 std::string bmcVersion;
495 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800496 {
497 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800498 }
499
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530500 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800501 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800502 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800503 MetaRevision revision = rev.value();
504 bmcMajor = revision.major;
505
506 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
507 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
508 }
509
510 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530511 std::string meVersion;
512 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800513 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800514 return false;
515 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530516 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
517 constexpr size_t matchedPhosphor = 6;
518 std::smatch results;
519 if (std::regex_match(meVersion, results, pattern1))
520 {
521 if (results.size() == matchedPhosphor)
522 {
523 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
Jayaprakash Mutyalad0657022021-08-26 21:18:08 +0000524 meMinor = static_cast<uint8_t>(std::stoi(results[2]) << 4 |
525 std::stoi(results[3]));
AppaRao Puli32825a22020-01-17 15:52:41 +0530526 }
527 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800528 return true;
529}
530
531ipmi::RspType<
532 std::variant<std::string,
533 std::tuple<uint8_t, std::array<uint8_t, 2>,
534 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
535 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
536 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530537 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
538 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530539 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800540{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800541 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
542 {
543 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800544 }
545
546 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800547 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800548 {
549 case OEMDevEntityType::biosId:
550 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530551 // Byte 2&3, Only used with selecting BIOS
552 if (!countToRead || !offset)
553 {
554 return ipmi::responseReqDataLenInvalid();
555 }
556
Vernon Mauery15419dd2019-05-24 09:40:30 -0700557 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800558 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000559 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800560 try
561 {
Yong Li2742b852019-12-16 14:55:11 +0800562 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000563 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800564 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700565 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530566 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800567 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800568 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800569 }
Jason M. Bills64796042018-10-03 16:51:55 -0700570 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530571 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700572 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530573 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700574 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800575 else
576 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530577 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800578 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800579
580 std::string readBuf = {0};
581 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530582 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800583 (readBuf.begin()));
584 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800585 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500586 catch (const std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800587 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800588 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800589 }
590 }
591 break;
592
593 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800594 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530595 // Byte 2&3, Only used with selecting BIOS
596 if (countToRead || offset)
597 {
598 return ipmi::responseReqDataLenInvalid();
599 }
600
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800601 constexpr const size_t verLen = 2;
602 constexpr const size_t verTotalLen = 10;
603 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
604 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
605 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
606 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
607 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
608 // data0/1: BMC version number; data6/7: ME version number
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530609 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800610 {
611 return ipmi::responseUnspecifiedError();
612 }
Jayaprakash Mutyala90da3d92021-11-18 22:01:22 +0000613 if (!getHscVerInfo(ctx, hsc0Buf[0], hsc0Buf[1], hsc1Buf[0],
614 hsc1Buf[1], hsc2Buf[0], hsc2Buf[1]))
615 {
616 return ipmi::responseUnspecifiedError();
617 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800618 return ipmi::responseSuccess(
619 std::tuple<
620 uint8_t, std::array<uint8_t, verLen>,
621 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
622 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
623 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
624 }
625 break;
626
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800627 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800628 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530629 // Byte 2&3, Only used with selecting BIOS
630 if (countToRead || offset)
631 {
632 return ipmi::responseReqDataLenInvalid();
633 }
634
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800635 constexpr const size_t sdrLen = 2;
636 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
637 return ipmi::responseSuccess(
638 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
639 readBuf});
640 }
641 break;
642
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800643 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800644 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800645 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800646}
647
648ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
649 ipmi_request_t request, ipmi_response_t response,
650 ipmi_data_len_t dataLen, ipmi_context_t context)
651{
652 if (*dataLen != 0)
653 {
Jason M. Bills64796042018-10-03 16:51:55 -0700654 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800655 return IPMI_CC_REQ_DATA_LEN_INVALID;
656 }
657
658 *dataLen = 1;
659 uint8_t* res = reinterpret_cast<uint8_t*>(response);
660 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
661 // AIC is available so that BIOS will not timeout repeatly which leads to
662 // slow booting.
663 *res = 0; // Byte1=Count of SlotPosition/FruID records.
664 return IPMI_CC_OK;
665}
666
Jason M. Bills64796042018-10-03 16:51:55 -0700667ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
668 ipmi_request_t request,
669 ipmi_response_t response,
670 ipmi_data_len_t dataLen,
671 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800672{
Jason M. Bills64796042018-10-03 16:51:55 -0700673 GetPowerRestoreDelayRes* resp =
674 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
675
676 if (*dataLen != 0)
677 {
678 *dataLen = 0;
679 return IPMI_CC_REQ_DATA_LEN_INVALID;
680 }
681
Vernon Mauery15419dd2019-05-24 09:40:30 -0700682 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700683 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700684 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700685 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700686 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700687 powerRestoreDelayIntf, powerRestoreDelayProp);
688
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700689 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700690 resp->byteLSB = delay;
691 resp->byteMSB = delay >> 8;
692
693 *dataLen = sizeof(GetPowerRestoreDelayRes);
694
695 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800696}
697
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800698static uint8_t bcdToDec(uint8_t val)
699{
700 return ((val / 16 * 10) + (val % 16));
701}
702
703// Allows an update utility or system BIOS to send the status of an embedded
704// firmware update attempt to the BMC. After received, BMC will create a logging
705// record.
706ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
707 uint8_t majorRevision,
708 uint8_t minorRevision,
709 uint32_t auxInfo)
710{
711 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700712 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800713 target = (target & selEvtTargetMask) >> selEvtTargetShift;
714
715 /* make sure the status is 0, 1, or 2 as per the spec */
716 if (status > 2)
717 {
718 return ipmi::response(ipmi::ccInvalidFieldRequest);
719 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700720 /* make sure the target is 0, 1, 2, or 4 as per the spec */
721 if (target > 4 || target == 3)
722 {
723 return ipmi::response(ipmi::ccInvalidFieldRequest);
724 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800725 /*orignal OEM command is to record OEM SEL.
726 But openbmc does not support OEM SEL, so we redirect it to redfish event
727 logging. */
728 std::string buildInfo;
729 std::string action;
730 switch (FWUpdateTarget(target))
731 {
732 case FWUpdateTarget::targetBMC:
733 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700734 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800735 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
736 " BuildID: " + std::to_string(auxInfo);
737 buildInfo += std::to_string(auxInfo);
738 break;
739 case FWUpdateTarget::targetBIOS:
740 firmware = "BIOS";
741 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700742 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800743 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
744 " minor: " +
745 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
746 " ReleaseNumber: " + // ASCII encoded
747 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
748 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
749 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
750 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
751 break;
752 case FWUpdateTarget::targetME:
753 firmware = "ME";
754 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700755 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800756 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
757 " minor2: " +
758 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
759 " build1: " +
760 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
761 " build2: " +
762 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
763 break;
764 case FWUpdateTarget::targetOEMEWS:
765 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700766 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800767 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
768 " BuildID: " + std::to_string(auxInfo);
769 break;
770 }
771
Jason M. Billsdc249272019-04-03 09:58:40 -0700772 static const std::string openBMCMessageRegistryVersion("0.1");
773 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
774
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800775 switch (status)
776 {
777 case 0x0:
778 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700779 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800780 break;
781 case 0x1:
782 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700783 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800784 break;
785 case 0x2:
786 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700787 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800788 break;
789 default:
790 action = "unknown";
791 break;
792 }
793
Jason M. Billsdc249272019-04-03 09:58:40 -0700794 std::string firmwareInstanceStr =
795 firmware + " instance: " + std::to_string(instance);
796 std::string message("[firmware update] " + firmwareInstanceStr +
797 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800798
799 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700800 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
801 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
802 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800803 return ipmi::responseSuccess();
804}
805
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530806ipmi::RspType<uint8_t, std::vector<uint8_t>>
807 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
808 uint2_t slotNumber, uint3_t baseBoardSlotNum,
809 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
810 uint8_t netFn, uint8_t cmd,
811 std::optional<std::vector<uint8_t>> writeData)
812{
813 if (reserved1 || reserved2)
814 {
815 return ipmi::responseInvalidFieldRequest();
816 }
817
818 boost::system::error_code ec;
819 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
820 std::vector<uint8_t>>;
821 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
822 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
823 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
824 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
825 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
826 *writeData);
827 if (ec)
828 {
829 phosphor::logging::log<phosphor::logging::level::ERR>(
830 "Failed to call dbus method SlotIpmbRequest");
831 return ipmi::responseUnspecifiedError();
832 }
833
834 std::vector<uint8_t> dataReceived(0);
835 int status = -1;
836 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
837
838 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
839
840 if (status)
841 {
842 phosphor::logging::log<phosphor::logging::level::ERR>(
843 "Failed to get response from SlotIpmbRequest");
844 return ipmi::responseResponseError();
845 }
846 return ipmi::responseSuccess(cc, dataReceived);
847}
848
Jason M. Bills64796042018-10-03 16:51:55 -0700849ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
850 ipmi_request_t request,
851 ipmi_response_t response,
852 ipmi_data_len_t dataLen,
853 ipmi_context_t context)
854{
855 SetPowerRestoreDelayReq* data =
856 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
857 uint16_t delay = 0;
858
859 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
860 {
861 *dataLen = 0;
862 return IPMI_CC_REQ_DATA_LEN_INVALID;
863 }
864 delay = data->byteMSB;
865 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700866 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700867 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700868 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
869 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700870 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
871 *dataLen = 0;
872
873 return IPMI_CC_OK;
874}
875
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700876static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700877{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700878 static constexpr const char* cpuPresencePathPrefix =
879 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
880 static constexpr const char* cpuPresenceIntf =
881 "xyz.openbmc_project.Inventory.Item";
882 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
883 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
884 try
Jason M. Bills64796042018-10-03 16:51:55 -0700885 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700886 auto service =
887 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
888
889 ipmi::Value result = ipmi::getDbusProperty(
890 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
891 return std::get<bool>(result);
892 }
893 catch (const std::exception& e)
894 {
895 phosphor::logging::log<phosphor::logging::level::INFO>(
896 "Cannot find processor presence",
897 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
898 return false;
899 }
900}
901
902ipmi::RspType<bool, // CATERR Reset Enabled
903 bool, // ERR2 Reset Enabled
904 uint6_t, // reserved
905 uint8_t, // reserved, returns 0x3F
906 uint6_t, // CPU1 CATERR Count
907 uint2_t, // CPU1 Status
908 uint6_t, // CPU2 CATERR Count
909 uint2_t, // CPU2 Status
910 uint6_t, // CPU3 CATERR Count
911 uint2_t, // CPU3 Status
912 uint6_t, // CPU4 CATERR Count
913 uint2_t, // CPU4 Status
914 uint8_t // Crashdump Count
915 >
916 ipmiOEMGetProcessorErrConfig()
917{
918 bool resetOnCATERR = false;
919 bool resetOnERR2 = false;
920 uint6_t cpu1CATERRCount = 0;
921 uint6_t cpu2CATERRCount = 0;
922 uint6_t cpu3CATERRCount = 0;
923 uint6_t cpu4CATERRCount = 0;
924 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700925 uint2_t cpu1Status = cpuPresent("CPU_1")
926 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
927 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
928 uint2_t cpu2Status = cpuPresent("CPU_2")
929 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
930 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
931 uint2_t cpu3Status = cpuPresent("CPU_3")
932 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
933 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
934 uint2_t cpu4Status = cpuPresent("CPU_4")
935 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
936 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700937
938 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
939 try
940 {
941 auto service = ipmi::getService(*busp, processorErrConfigIntf,
942 processorErrConfigObjPath);
943
944 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
945 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
946 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
947 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
948 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
949 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
950 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
951 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
952 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
953 }
954 catch (const std::exception& e)
955 {
956 phosphor::logging::log<phosphor::logging::level::ERR>(
957 "Failed to fetch processor error config",
958 phosphor::logging::entry("ERROR=%s", e.what()));
959 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700960 }
961
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700962 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
963 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
964 cpu2Status, cpu3CATERRCount, cpu3Status,
965 cpu4CATERRCount, cpu4Status, crashdumpCount);
966}
Jason M. Bills64796042018-10-03 16:51:55 -0700967
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700968ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
969 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
970 std::optional<bool> clearCPUErrorCount,
971 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
972{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000973 if (reserved1 || reserved2)
974 {
975 return ipmi::responseInvalidFieldRequest();
976 }
977
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700978 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700979
980 try
981 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000982 if (reserved3.value_or(0))
983 {
984 return ipmi::responseInvalidFieldRequest();
985 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700986 auto service = ipmi::getService(*busp, processorErrConfigIntf,
987 processorErrConfigObjPath);
988 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
989 processorErrConfigIntf, "ResetOnCATERR",
990 resetOnCATERR);
991 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
992 processorErrConfigIntf, "ResetOnERR2",
993 resetOnERR2);
994 if (clearCPUErrorCount.value_or(false))
995 {
996 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700997 processorErrConfigIntf, "ErrorCountCPU1",
998 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700999 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001000 processorErrConfigIntf, "ErrorCountCPU2",
1001 static_cast<uint8_t>(0));
1002 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1003 processorErrConfigIntf, "ErrorCountCPU3",
1004 static_cast<uint8_t>(0));
1005 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
1006 processorErrConfigIntf, "ErrorCountCPU4",
1007 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001008 }
1009 if (clearCrashdumpCount.value_or(false))
1010 {
1011 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -07001012 processorErrConfigIntf, "CrashdumpCount",
1013 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001014 }
Jason M. Bills64796042018-10-03 16:51:55 -07001015 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001016 catch (const std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -07001017 {
Kuiying Wangbc546672018-11-23 15:41:05 +08001018 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001019 "Failed to set processor error config",
1020 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1021 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -07001022 }
1023
Jason M. Bills42bd9c82019-06-28 16:39:34 -07001024 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -07001025}
1026
Yong Li703922d2018-11-06 13:25:31 +08001027ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1028 ipmi_request_t request,
1029 ipmi_response_t response,
1030 ipmi_data_len_t dataLen,
1031 ipmi_context_t context)
1032{
1033 GetOEMShutdownPolicyRes* resp =
1034 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
1035
1036 if (*dataLen != 0)
1037 {
1038 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +08001039 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +08001040 *dataLen = 0;
1041 return IPMI_CC_REQ_DATA_LEN_INVALID;
1042 }
1043
1044 *dataLen = 0;
1045
1046 try
1047 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001048 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +08001049 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001050 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
1051 Value variant = getDbusProperty(
1052 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
1053 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +08001054
1055 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1056 convertPolicyFromString(std::get<std::string>(variant)) ==
1057 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1058 NoShutdownOnOCOT)
1059 {
1060 resp->policy = 0;
1061 }
1062 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1063 convertPolicyFromString(std::get<std::string>(variant)) ==
1064 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1065 Policy::ShutdownOnOCOT)
1066 {
1067 resp->policy = 1;
1068 }
1069 else
1070 {
1071 phosphor::logging::log<phosphor::logging::level::ERR>(
1072 "oem_set_shutdown_policy: invalid property!",
1073 phosphor::logging::entry(
1074 "PROP=%s", std::get<std::string>(variant).c_str()));
1075 return IPMI_CC_UNSPECIFIED_ERROR;
1076 }
Yong Li703922d2018-11-06 13:25:31 +08001077 // TODO needs to check if it is multi-node products,
1078 // policy is only supported on node 3/4
1079 resp->policySupport = shutdownPolicySupported;
1080 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001081 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001082 {
1083 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1084 return IPMI_CC_UNSPECIFIED_ERROR;
1085 }
1086
1087 *dataLen = sizeof(GetOEMShutdownPolicyRes);
1088 return IPMI_CC_OK;
1089}
1090
1091ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1092 ipmi_request_t request,
1093 ipmi_response_t response,
1094 ipmi_data_len_t dataLen,
1095 ipmi_context_t context)
1096{
1097 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +08001098 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
1099 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
1100 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +08001101
1102 // TODO needs to check if it is multi-node products,
1103 // policy is only supported on node 3/4
1104 if (*dataLen != 1)
1105 {
1106 phosphor::logging::log<phosphor::logging::level::ERR>(
1107 "oem_set_shutdown_policy: invalid input len!");
1108 *dataLen = 0;
1109 return IPMI_CC_REQ_DATA_LEN_INVALID;
1110 }
1111
1112 *dataLen = 0;
1113 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
1114 {
1115 phosphor::logging::log<phosphor::logging::level::ERR>(
1116 "oem_set_shutdown_policy: invalid input!");
1117 return IPMI_CC_INVALID_FIELD_REQUEST;
1118 }
1119
Yong Li0669d192019-05-06 14:01:46 +08001120 if (*req == noShutdownOnOCOT)
1121 {
1122 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1123 Policy::NoShutdownOnOCOT;
1124 }
1125 else
1126 {
1127 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
1128 Policy::ShutdownOnOCOT;
1129 }
1130
Yong Li703922d2018-11-06 13:25:31 +08001131 try
1132 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001133 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +08001134 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001135 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +08001136 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001137 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +08001138 oemShutdownPolicyObjPathProp,
1139 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +08001140 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001141 catch (const sdbusplus::exception_t& e)
Yong Li703922d2018-11-06 13:25:31 +08001142 {
1143 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1144 return IPMI_CC_UNSPECIFIED_ERROR;
1145 }
1146
1147 return IPMI_CC_OK;
1148}
1149
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301150/** @brief implementation for check the DHCP or not in IPv4
1151 * @param[in] Channel - Channel number
1152 * @returns true or false.
1153 */
1154static bool isDHCPEnabled(uint8_t Channel)
1155{
1156 try
1157 {
1158 auto ethdevice = getChannelName(Channel);
1159 if (ethdevice.empty())
1160 {
1161 return false;
1162 }
1163 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001164 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301165 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001166 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1167 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301168 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001169 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301170 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1171 {
1172 return true;
1173 }
1174 else
1175 {
1176 return false;
1177 }
1178 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001179 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301180 {
1181 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1182 return true;
1183 }
1184}
1185
1186/** @brief implementes for check the DHCP or not in IPv6
1187 * @param[in] Channel - Channel number
1188 * @returns true or false.
1189 */
1190static bool isDHCPIPv6Enabled(uint8_t Channel)
1191{
1192
1193 try
1194 {
1195 auto ethdevice = getChannelName(Channel);
1196 if (ethdevice.empty())
1197 {
1198 return false;
1199 }
1200 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001201 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301202 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001203 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1204 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301205 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001206 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301207 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1208 {
1209 return true;
1210 }
1211 else
1212 {
1213 return false;
1214 }
1215 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001216 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301217 {
1218 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1219 return true;
1220 }
1221}
1222
1223/** @brief implementes the creating of default new user
1224 * @param[in] userName - new username in 16 bytes.
1225 * @param[in] userPassword - new password in 20 bytes
1226 * @returns ipmi completion code.
1227 */
1228ipmi::RspType<> ipmiOEMSetUser2Activation(
1229 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001230 const SecureBuffer& userPassword)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301231{
Vernon Mauery3b3d29b2021-08-05 15:03:35 -07001232 if (userPassword.size() != ipmi::maxIpmi20PasswordSize)
1233 {
1234 return ipmi::responseReqDataLenInvalid();
1235 }
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301236 bool userState = false;
1237 // Check for System Interface not exist and LAN should be static
1238 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1239 {
Manish Baing440f62b2021-07-15 22:00:37 +00001240 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301241 try
1242 {
1243 getChannelInfo(channel, chInfo);
1244 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001245 catch (const sdbusplus::exception_t& e)
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301246 {
1247 phosphor::logging::log<phosphor::logging::level::ERR>(
1248 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1249 phosphor::logging::entry("MSG: %s", e.description()));
1250 return ipmi::response(ipmi::ccUnspecifiedError);
1251 }
1252 if (chInfo.mediumType ==
1253 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1254 {
1255 phosphor::logging::log<phosphor::logging::level::ERR>(
1256 "ipmiOEMSetUser2Activation: system interface exist .");
1257 return ipmi::response(ipmi::ccCommandNotAvailable);
1258 }
1259 else
1260 {
1261
1262 if (chInfo.mediumType ==
1263 static_cast<uint8_t>(EChannelMediumType::lan8032))
1264 {
1265 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1266 {
1267 phosphor::logging::log<phosphor::logging::level::ERR>(
1268 "ipmiOEMSetUser2Activation: DHCP enabled .");
1269 return ipmi::response(ipmi::ccCommandNotAvailable);
1270 }
1271 }
1272 }
1273 }
1274 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1275 if (ipmi::ccSuccess ==
1276 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1277 {
1278 if (enabledUsers > 1)
1279 {
1280 phosphor::logging::log<phosphor::logging::level::ERR>(
1281 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1282 return ipmi::response(ipmi::ccCommandNotAvailable);
1283 }
1284 // Check the user 2 is enabled or not
1285 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1286 if (userState == true)
1287 {
1288 phosphor::logging::log<phosphor::logging::level::ERR>(
1289 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1290 return ipmi::response(ipmi::ccCommandNotAvailable);
1291 }
1292 }
1293 else
1294 {
1295 return ipmi::response(ipmi::ccUnspecifiedError);
1296 }
1297
1298#if BYTE_ORDER == LITTLE_ENDIAN
1299 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1300#endif
1301#if BYTE_ORDER == BIG_ENDIAN
1302 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1303#endif
1304
Vernon Mauery037cabd2020-05-14 12:16:01 -07001305 // ipmiUserSetUserName correctly handles char*, possibly non-null
1306 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001307 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1308 sizeof(userName));
1309 const std::string userNameRaw(
1310 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001311
Vernon Mauery037cabd2020-05-14 12:16:01 -07001312 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301313 {
1314 if (ipmi::ccSuccess ==
1315 ipmiUserSetUserPassword(
1316 ipmiDefaultUserId,
1317 reinterpret_cast<const char*>(userPassword.data())))
1318 {
1319 if (ipmi::ccSuccess ==
1320 ipmiUserSetPrivilegeAccess(
1321 ipmiDefaultUserId,
1322 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1323 privAccess, true))
1324 {
1325 phosphor::logging::log<phosphor::logging::level::INFO>(
1326 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001327
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301328 return ipmi::responseSuccess();
1329 }
1330 }
1331 // we need to delete the default user id which added in this command as
1332 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001333 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301334 phosphor::logging::log<phosphor::logging::level::ERR>(
1335 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1336 }
1337 else
1338 {
1339 phosphor::logging::log<phosphor::logging::level::ERR>(
1340 "ipmiOEMSetUser2Activation: Setting username failed.");
1341 }
1342
1343 return ipmi::response(ipmi::ccCommandNotAvailable);
1344}
1345
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301346/** @brief implementes executing the linux command
1347 * @param[in] linux command
1348 * @returns status
1349 */
1350
1351static uint8_t executeCmd(const char* path)
1352{
1353 boost::process::child execProg(path);
1354 execProg.wait();
1355
1356 int retCode = execProg.exit_code();
1357 if (retCode)
1358 {
1359 return ipmi::ccUnspecifiedError;
1360 }
1361 return ipmi::ccSuccess;
1362}
1363
1364/** @brief implementes ASD Security event logging
1365 * @param[in] Event message string
1366 * @param[in] Event Severity
1367 * @returns status
1368 */
1369
1370static void atScaleDebugEventlog(std::string msg, int severity)
1371{
1372 std::string eventStr = "OpenBMC.0.1." + msg;
1373 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1374 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1375 eventStr.c_str(), NULL);
1376}
1377
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301378/** @brief implementes setting password for special user
1379 * @param[in] specialUserIndex
1380 * @param[in] userPassword - new password in 20 bytes
1381 * @returns ipmi completion code.
1382 */
1383ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1384 uint8_t specialUserIndex,
1385 std::vector<uint8_t> userPassword)
1386{
1387 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301388 ipmi_ret_t status = ipmi::ccSuccess;
1389
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301390 try
1391 {
1392 getChannelInfo(ctx->channel, chInfo);
1393 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001394 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301395 {
1396 phosphor::logging::log<phosphor::logging::level::ERR>(
1397 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1398 phosphor::logging::entry("MSG: %s", e.description()));
1399 return ipmi::responseUnspecifiedError();
1400 }
1401 if (chInfo.mediumType !=
1402 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1403 {
1404 phosphor::logging::log<phosphor::logging::level::ERR>(
1405 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1406 "interface");
1407 return ipmi::responseCommandNotAvailable();
1408 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301409
1410 // 0 for root user and 1 for AtScaleDebug is allowed
1411 if (specialUserIndex >
1412 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301413 {
1414 phosphor::logging::log<phosphor::logging::level::ERR>(
1415 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1416 return ipmi::responseParmOutOfRange();
1417 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301418 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301419 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301420 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001421 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301422 if (userPassword.size() < minPasswordSizeRequired ||
1423 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1424 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001425 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301426 return ipmi::responseReqDataLenInvalid();
1427 }
1428 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1429 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001430 // Clear sensitive data
1431 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301432 if (specialUserIndex ==
1433 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1434 {
1435 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1436
1437 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1438 }
1439 else
1440 {
1441 status = ipmiSetSpecialUserPassword("root", passwd);
1442 }
1443 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301444 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301445 else
1446 {
1447 if (specialUserIndex ==
1448 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1449 {
1450 status = executeCmd("passwd -d root");
1451 }
1452 else
1453 {
1454
1455 status = executeCmd("passwd -d asdbg");
1456
1457 if (status == 0)
1458 {
1459 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1460 LOG_INFO);
1461 }
1462 }
1463 return ipmi::response(status);
1464 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301465}
1466
Kuiying Wang45f04982018-12-26 09:23:08 +08001467namespace ledAction
1468{
1469using namespace sdbusplus::xyz::openbmc_project::Led::server;
1470std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001471 {Physical::Action::Off, 0},
1472 {Physical::Action::On, 2},
1473 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001474
1475std::map<uint8_t, std::string> offsetObjPath = {
1476 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1477
1478} // namespace ledAction
1479
1480int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1481 const std::string& objPath, uint8_t& state)
1482{
1483 try
1484 {
1485 std::string service = getService(bus, intf, objPath);
1486 Value stateValue =
1487 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001488 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001489 state = ledAction::actionDbusToIpmi.at(
1490 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1491 convertActionFromString(strState));
1492 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001493 catch (const sdbusplus::exception::exception& e)
Kuiying Wang45f04982018-12-26 09:23:08 +08001494 {
1495 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1496 return -1;
1497 }
1498 return 0;
1499}
1500
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001501ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001502{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001503 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001504 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001505 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001506 for (auto it = ledAction::offsetObjPath.begin();
1507 it != ledAction::offsetObjPath.end(); ++it)
1508 {
1509 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001510 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001511 {
1512 phosphor::logging::log<phosphor::logging::level::ERR>(
1513 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001514 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001515 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001516 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001517 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001518 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001519}
1520
Yong Li23737fe2019-02-19 08:49:55 +08001521ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1522 ipmi_request_t request,
1523 ipmi_response_t response,
1524 ipmi_data_len_t dataLen,
1525 ipmi_context_t context)
1526{
1527 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1528 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1529
1530 if (*dataLen == 0)
1531 {
1532 phosphor::logging::log<phosphor::logging::level::ERR>(
1533 "CfgHostSerial: invalid input len!",
1534 phosphor::logging::entry("LEN=%d", *dataLen));
1535 return IPMI_CC_REQ_DATA_LEN_INVALID;
1536 }
1537
1538 switch (req->command)
1539 {
1540 case getHostSerialCfgCmd:
1541 {
1542 if (*dataLen != 1)
1543 {
1544 phosphor::logging::log<phosphor::logging::level::ERR>(
1545 "CfgHostSerial: invalid input len!");
1546 *dataLen = 0;
1547 return IPMI_CC_REQ_DATA_LEN_INVALID;
1548 }
1549
1550 *dataLen = 0;
1551
1552 boost::process::ipstream is;
1553 std::vector<std::string> data;
1554 std::string line;
1555 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1556 boost::process::std_out > is);
1557
1558 while (c1.running() && std::getline(is, line) && !line.empty())
1559 {
1560 data.push_back(line);
1561 }
1562
1563 c1.wait();
1564 if (c1.exit_code())
1565 {
1566 phosphor::logging::log<phosphor::logging::level::ERR>(
1567 "CfgHostSerial:: error on execute",
1568 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1569 // Using the default value
1570 *resp = 0;
1571 }
1572 else
1573 {
1574 if (data.size() != 1)
1575 {
1576 phosphor::logging::log<phosphor::logging::level::ERR>(
1577 "CfgHostSerial:: error on read env");
1578 return IPMI_CC_UNSPECIFIED_ERROR;
1579 }
1580 try
1581 {
1582 unsigned long tmp = std::stoul(data[0]);
1583 if (tmp > std::numeric_limits<uint8_t>::max())
1584 {
1585 throw std::out_of_range("Out of range");
1586 }
1587 *resp = static_cast<uint8_t>(tmp);
1588 }
1589 catch (const std::invalid_argument& e)
1590 {
1591 phosphor::logging::log<phosphor::logging::level::ERR>(
1592 "invalid config ",
1593 phosphor::logging::entry("ERR=%s", e.what()));
1594 return IPMI_CC_UNSPECIFIED_ERROR;
1595 }
1596 catch (const std::out_of_range& e)
1597 {
1598 phosphor::logging::log<phosphor::logging::level::ERR>(
1599 "out_of_range config ",
1600 phosphor::logging::entry("ERR=%s", e.what()));
1601 return IPMI_CC_UNSPECIFIED_ERROR;
1602 }
1603 }
1604
1605 *dataLen = 1;
1606 break;
1607 }
1608 case setHostSerialCfgCmd:
1609 {
1610 if (*dataLen != sizeof(CfgHostSerialReq))
1611 {
1612 phosphor::logging::log<phosphor::logging::level::ERR>(
1613 "CfgHostSerial: invalid input len!");
1614 *dataLen = 0;
1615 return IPMI_CC_REQ_DATA_LEN_INVALID;
1616 }
1617
1618 *dataLen = 0;
1619
1620 if (req->parameter > HostSerialCfgParamMax)
1621 {
1622 phosphor::logging::log<phosphor::logging::level::ERR>(
1623 "CfgHostSerial: invalid input!");
1624 return IPMI_CC_INVALID_FIELD_REQUEST;
1625 }
1626
1627 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1628 std::to_string(req->parameter));
1629
1630 c1.wait();
1631 if (c1.exit_code())
1632 {
1633 phosphor::logging::log<phosphor::logging::level::ERR>(
1634 "CfgHostSerial:: error on execute",
1635 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1636 return IPMI_CC_UNSPECIFIED_ERROR;
1637 }
1638 break;
1639 }
1640 default:
1641 phosphor::logging::log<phosphor::logging::level::ERR>(
1642 "CfgHostSerial: invalid input!");
1643 *dataLen = 0;
1644 return IPMI_CC_INVALID_FIELD_REQUEST;
1645 }
1646
1647 return IPMI_CC_OK;
1648}
1649
James Feist91244a62019-02-19 15:04:54 -08001650constexpr const char* thermalModeInterface =
1651 "xyz.openbmc_project.Control.ThermalMode";
1652constexpr const char* thermalModePath =
1653 "/xyz/openbmc_project/control/thermal_mode";
1654
1655bool getFanProfileInterface(
1656 sdbusplus::bus::bus& bus,
1657 boost::container::flat_map<
1658 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1659{
1660 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1661 "GetAll");
1662 call.append(thermalModeInterface);
1663 try
1664 {
1665 auto data = bus.call(call);
1666 data.read(resp);
1667 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001668 catch (const sdbusplus::exception_t& e)
James Feist91244a62019-02-19 15:04:54 -08001669 {
1670 phosphor::logging::log<phosphor::logging::level::ERR>(
1671 "getFanProfileInterface: can't get thermal mode!",
1672 phosphor::logging::entry("ERR=%s", e.what()));
1673 return false;
1674 }
1675 return true;
1676}
1677
anil kumar appanaf945eee2019-09-25 23:29:11 +00001678/**@brief implements the OEM set fan config.
1679 * @param selectedFanProfile - fan profile to enable
1680 * @param reserved1
1681 * @param performanceMode - Performance/Acoustic mode
1682 * @param reserved2
1683 * @param setPerformanceMode - set Performance/Acoustic mode
1684 * @param setFanProfile - set fan profile
1685 *
1686 * @return IPMI completion code.
1687 **/
1688ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1689
1690 uint2_t reserved1, bool performanceMode,
1691 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301692 bool setFanProfile,
1693 std::optional<uint8_t> dimmGroupId,
1694 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001695{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001696 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001697 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001698 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001699 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301700
1701 if (dimmGroupId)
1702 {
1703 if (*dimmGroupId >= maxCPUNum)
1704 {
1705 return ipmi::responseInvalidFieldRequest();
1706 }
1707 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1708 {
1709 return ipmi::responseInvalidFieldRequest();
1710 }
1711 }
1712
James Feist91244a62019-02-19 15:04:54 -08001713 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001714 boost::container::flat_map<
1715 std::string, std::variant<std::vector<std::string>, std::string>>
1716 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001717 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1718 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001719 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001720 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001721 }
1722
1723 std::vector<std::string>* supported =
1724 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1725 if (supported == nullptr)
1726 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001727 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001728 }
1729 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001730 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001731 {
James Feist91244a62019-02-19 15:04:54 -08001732 if (performanceMode)
1733 {
1734
1735 if (std::find(supported->begin(), supported->end(),
1736 "Performance") != supported->end())
1737 {
1738 mode = "Performance";
1739 }
1740 }
1741 else
1742 {
James Feist91244a62019-02-19 15:04:54 -08001743 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1744 supported->end())
1745 {
1746 mode = "Acoustic";
1747 }
1748 }
1749 if (mode.empty())
1750 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001751 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001752 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001753
1754 try
1755 {
1756 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1757 thermalModeInterface, "Current", mode);
1758 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001759 catch (const sdbusplus::exception_t& e)
anil kumar appanaf945eee2019-09-25 23:29:11 +00001760 {
1761 phosphor::logging::log<phosphor::logging::level::ERR>(
1762 "ipmiOEMSetFanConfig: can't set thermal mode!",
1763 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1764 return ipmi::responseResponseError();
1765 }
James Feist91244a62019-02-19 15:04:54 -08001766 }
1767
anil kumar appanaf945eee2019-09-25 23:29:11 +00001768 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001769}
1770
James Feist5b693632019-07-09 09:06:09 -07001771ipmi::RspType<uint8_t, // profile support map
1772 uint8_t, // fan control profile enable
1773 uint8_t, // flags
1774 uint32_t // dimm presence bit map
1775 >
1776 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001777{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301778 if (dimmGroupId >= maxCPUNum)
1779 {
1780 return ipmi::responseInvalidFieldRequest();
1781 }
1782
1783 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1784
1785 if (!cpuStatus)
1786 {
1787 return ipmi::responseInvalidFieldRequest();
1788 }
1789
James Feist91244a62019-02-19 15:04:54 -08001790 boost::container::flat_map<
1791 std::string, std::variant<std::vector<std::string>, std::string>>
1792 profileData;
1793
Vernon Mauery15419dd2019-05-24 09:40:30 -07001794 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1795 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001796 {
James Feist5b693632019-07-09 09:06:09 -07001797 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001798 }
1799
1800 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1801
1802 if (current == nullptr)
1803 {
1804 phosphor::logging::log<phosphor::logging::level::ERR>(
1805 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001806 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001807 }
1808 bool performance = (*current == "Performance");
1809
James Feist5b693632019-07-09 09:06:09 -07001810 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001811 if (performance)
1812 {
James Feist5b693632019-07-09 09:06:09 -07001813 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001814 }
1815
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001816 constexpr uint8_t fanControlDefaultProfile = 0x80;
1817 constexpr uint8_t fanControlProfileState = 0x00;
1818 constexpr uint32_t dimmPresenceBitmap = 0x00;
1819
1820 return ipmi::responseSuccess(fanControlDefaultProfile,
1821 fanControlProfileState, flags,
1822 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001823}
James Feist5f957ca2019-03-14 15:33:55 -07001824constexpr const char* cfmLimitSettingPath =
1825 "/xyz/openbmc_project/control/cfm_limit";
1826constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001827constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001828constexpr const size_t legacyPCHSensorNumber = 0x22;
1829constexpr const char* exitAirPathName = "Exit_Air";
1830constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001831constexpr const char* pidConfigurationIface =
1832 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001833
James Feist09f6b602019-08-08 11:30:03 -07001834static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001835{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001836 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001837 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001838 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1839 "/xyz/openbmc_project/object_mapper",
1840 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001841
James Feistacc8a4e2019-04-02 14:23:57 -07001842 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001843 std::string path;
1844 GetSubTreeType resp;
1845 try
1846 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001847 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001848 reply.read(resp);
1849 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001850 catch (const sdbusplus::exception_t&)
James Feistfaa4f222019-03-21 16:21:55 -07001851 {
1852 phosphor::logging::log<phosphor::logging::level::ERR>(
1853 "ipmiOEMGetFscParameter: mapper error");
1854 };
James Feist09f6b602019-08-08 11:30:03 -07001855 auto config =
1856 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1857 return pair.first.find(name) != std::string::npos;
1858 });
James Feistfaa4f222019-03-21 16:21:55 -07001859 if (config != resp.end())
1860 {
1861 path = std::move(config->first);
1862 }
1863 return path;
1864}
James Feist5f957ca2019-03-14 15:33:55 -07001865
James Feistacc8a4e2019-04-02 14:23:57 -07001866// flat map to make alphabetical
1867static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1868{
1869 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001870 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001871 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001872 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1873 "/xyz/openbmc_project/object_mapper",
1874 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001875
1876 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1877 GetSubTreeType resp;
1878
1879 try
1880 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001881 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001882 reply.read(resp);
1883 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001884 catch (const sdbusplus::exception_t&)
James Feistacc8a4e2019-04-02 14:23:57 -07001885 {
1886 phosphor::logging::log<phosphor::logging::level::ERR>(
1887 "getFanConfigPaths: mapper error");
1888 };
1889 for (const auto& [path, objects] : resp)
1890 {
1891 if (objects.empty())
1892 {
1893 continue; // should be impossible
1894 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001895
1896 try
1897 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001898 ret.emplace(path,
1899 getAllDbusProperties(*dbus, objects[0].first, path,
1900 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001901 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05001902 catch (const sdbusplus::exception_t& e)
Zhu, Yungebe560b02019-04-21 21:19:21 -04001903 {
1904 phosphor::logging::log<phosphor::logging::level::ERR>(
1905 "getPidConfigs: can't get DbusProperties!",
1906 phosphor::logging::entry("ERR=%s", e.what()));
1907 }
James Feistacc8a4e2019-04-02 14:23:57 -07001908 }
1909 return ret;
1910}
1911
1912ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1913{
1914 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1915 if (data.empty())
1916 {
1917 return ipmi::responseResponseError();
1918 }
1919 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1920 for (const auto& [_, pid] : data)
1921 {
1922 auto findClass = pid.find("Class");
1923 if (findClass == pid.end())
1924 {
1925 phosphor::logging::log<phosphor::logging::level::ERR>(
1926 "ipmiOEMGetFscParameter: found illegal pid "
1927 "configurations");
1928 return ipmi::responseResponseError();
1929 }
1930 std::string type = std::get<std::string>(findClass->second);
1931 if (type == "fan")
1932 {
1933 auto findOutLimit = pid.find("OutLimitMin");
1934 if (findOutLimit == pid.end())
1935 {
1936 phosphor::logging::log<phosphor::logging::level::ERR>(
1937 "ipmiOEMGetFscParameter: found illegal pid "
1938 "configurations");
1939 return ipmi::responseResponseError();
1940 }
1941 // get the min out of all the offsets
1942 minOffset = std::min(
1943 minOffset,
1944 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1945 }
1946 }
1947 if (minOffset == std::numeric_limits<uint8_t>::max())
1948 {
1949 phosphor::logging::log<phosphor::logging::level::ERR>(
1950 "ipmiOEMGetFscParameter: found no fan configurations!");
1951 return ipmi::responseResponseError();
1952 }
1953
1954 return ipmi::responseSuccess(minOffset);
1955}
1956
1957ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1958{
Manish Baingbaa579f2021-10-08 22:30:32 +00001959 constexpr uint8_t maxFanSpeedOffset = 100;
1960 if (offset > maxFanSpeedOffset)
1961 {
1962 phosphor::logging::log<phosphor::logging::level::ERR>(
1963 "ipmiOEMSetFanSpeedOffset: fan offset greater than limit");
1964 return ipmi::responseInvalidFieldRequest();
1965 }
James Feistacc8a4e2019-04-02 14:23:57 -07001966 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1967 if (data.empty())
1968 {
1969
1970 phosphor::logging::log<phosphor::logging::level::ERR>(
1971 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1972 return ipmi::responseResponseError();
1973 }
1974
Vernon Mauery15419dd2019-05-24 09:40:30 -07001975 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001976 bool found = false;
1977 for (const auto& [path, pid] : data)
1978 {
1979 auto findClass = pid.find("Class");
1980 if (findClass == pid.end())
1981 {
1982
1983 phosphor::logging::log<phosphor::logging::level::ERR>(
1984 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1985 "configurations");
1986 return ipmi::responseResponseError();
1987 }
1988 std::string type = std::get<std::string>(findClass->second);
1989 if (type == "fan")
1990 {
1991 auto findOutLimit = pid.find("OutLimitMin");
1992 if (findOutLimit == pid.end())
1993 {
1994
1995 phosphor::logging::log<phosphor::logging::level::ERR>(
1996 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1997 "configurations");
1998 return ipmi::responseResponseError();
1999 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07002000 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07002001 path, pidConfigurationIface, "OutLimitMin",
2002 static_cast<double>(offset));
2003 found = true;
2004 }
2005 }
2006 if (!found)
2007 {
2008 phosphor::logging::log<phosphor::logging::level::ERR>(
2009 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
2010 return ipmi::responseResponseError();
2011 }
2012
2013 return ipmi::responseSuccess();
2014}
2015
2016ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
2017 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07002018{
2019 constexpr const size_t disableLimiting = 0x0;
2020
Vernon Mauery15419dd2019-05-24 09:40:30 -07002021 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002022 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002023 {
James Feist09f6b602019-08-08 11:30:03 -07002024 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07002025 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07002026 {
James Feist09f6b602019-08-08 11:30:03 -07002027 pathName = exitAirPathName;
2028 }
2029 else if (param1 == legacyPCHSensorNumber)
2030 {
2031 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07002032 }
2033 else
2034 {
James Feistacc8a4e2019-04-02 14:23:57 -07002035 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002036 }
James Feist09f6b602019-08-08 11:30:03 -07002037 std::string path = getConfigPath(pathName);
2038 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
2039 pidConfigurationIface, "SetPoint",
2040 static_cast<double>(param2));
2041 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07002042 }
James Feistacc8a4e2019-04-02 14:23:57 -07002043 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002044 {
James Feistacc8a4e2019-04-02 14:23:57 -07002045 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07002046
2047 // must be greater than 50 based on eps
2048 if (cfm < 50 && cfm != disableLimiting)
2049 {
James Feistacc8a4e2019-04-02 14:23:57 -07002050 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002051 }
2052
2053 try
2054 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002055 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07002056 cfmLimitIface, "Limit",
2057 static_cast<double>(cfm));
2058 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002059 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002060 {
2061 phosphor::logging::log<phosphor::logging::level::ERR>(
2062 "ipmiOEMSetFscParameter: can't set cfm setting!",
2063 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002064 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002065 }
James Feistacc8a4e2019-04-02 14:23:57 -07002066 return ipmi::responseSuccess();
2067 }
2068 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2069 {
2070 constexpr const size_t maxDomainCount = 8;
2071 uint8_t requestedDomainMask = param1;
2072 boost::container::flat_map data = getPidConfigs();
2073 if (data.empty())
2074 {
2075
2076 phosphor::logging::log<phosphor::logging::level::ERR>(
2077 "ipmiOEMSetFscParameter: found no pid configurations!");
2078 return ipmi::responseResponseError();
2079 }
2080 size_t count = 0;
2081 for (const auto& [path, pid] : data)
2082 {
2083 auto findClass = pid.find("Class");
2084 if (findClass == pid.end())
2085 {
2086
2087 phosphor::logging::log<phosphor::logging::level::ERR>(
2088 "ipmiOEMSetFscParameter: found illegal pid "
2089 "configurations");
2090 return ipmi::responseResponseError();
2091 }
2092 std::string type = std::get<std::string>(findClass->second);
2093 if (type == "fan")
2094 {
2095 if (requestedDomainMask & (1 << count))
2096 {
2097 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002098 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07002099 pidConfigurationIface, "OutLimitMax",
2100 static_cast<double>(param2));
2101 }
2102 count++;
2103 }
2104 }
2105 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07002106 }
2107 else
2108 {
2109 // todo other command parts possibly
2110 // tcontrol is handled in peci now
2111 // fan speed offset not implemented yet
2112 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002113 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002114 }
2115}
2116
James Feistacc8a4e2019-04-02 14:23:57 -07002117ipmi::RspType<
2118 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
2119 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07002120{
James Feist09f6b602019-08-08 11:30:03 -07002121 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07002122
Vernon Mauery15419dd2019-05-24 09:40:30 -07002123 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07002124 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07002125 {
James Feistacc8a4e2019-04-02 14:23:57 -07002126 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07002127 {
James Feistacc8a4e2019-04-02 14:23:57 -07002128 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07002129 }
2130
James Feist09f6b602019-08-08 11:30:03 -07002131 std::string pathName;
2132
2133 if (*param == legacyExitAirSensorNumber)
2134 {
2135 pathName = exitAirPathName;
2136 }
2137 else if (*param == legacyPCHSensorNumber)
2138 {
2139 pathName = pchPathName;
2140 }
2141 else
James Feistfaa4f222019-03-21 16:21:55 -07002142 {
James Feistacc8a4e2019-04-02 14:23:57 -07002143 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07002144 }
James Feist09f6b602019-08-08 11:30:03 -07002145
2146 uint8_t setpoint = legacyDefaultSetpoint;
2147 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07002148 if (path.size())
2149 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002150 Value val = ipmi::getDbusProperty(
2151 *dbus, "xyz.openbmc_project.EntityManager", path,
2152 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07002153 setpoint = std::floor(std::get<double>(val) + 0.5);
2154 }
2155
2156 // old implementation used to return the "default" and current, we
2157 // don't make the default readily available so just make both the
2158 // same
James Feistfaa4f222019-03-21 16:21:55 -07002159
James Feistacc8a4e2019-04-02 14:23:57 -07002160 return ipmi::responseSuccess(
2161 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07002162 }
James Feistacc8a4e2019-04-02 14:23:57 -07002163 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
2164 {
2165 constexpr const size_t maxDomainCount = 8;
2166
2167 if (!param)
2168 {
2169 return ipmi::responseReqDataLenInvalid();
2170 }
2171 uint8_t requestedDomain = *param;
2172 if (requestedDomain >= maxDomainCount)
2173 {
2174 return ipmi::responseInvalidFieldRequest();
2175 }
2176
2177 boost::container::flat_map data = getPidConfigs();
2178 if (data.empty())
2179 {
2180 phosphor::logging::log<phosphor::logging::level::ERR>(
2181 "ipmiOEMGetFscParameter: found no pid configurations!");
2182 return ipmi::responseResponseError();
2183 }
2184 size_t count = 0;
2185 for (const auto& [_, pid] : data)
2186 {
2187 auto findClass = pid.find("Class");
2188 if (findClass == pid.end())
2189 {
2190 phosphor::logging::log<phosphor::logging::level::ERR>(
2191 "ipmiOEMGetFscParameter: found illegal pid "
2192 "configurations");
2193 return ipmi::responseResponseError();
2194 }
2195 std::string type = std::get<std::string>(findClass->second);
2196 if (type == "fan")
2197 {
2198 if (requestedDomain == count)
2199 {
2200 auto findOutLimit = pid.find("OutLimitMax");
2201 if (findOutLimit == pid.end())
2202 {
2203 phosphor::logging::log<phosphor::logging::level::ERR>(
2204 "ipmiOEMGetFscParameter: found illegal pid "
2205 "configurations");
2206 return ipmi::responseResponseError();
2207 }
2208
2209 return ipmi::responseSuccess(
2210 static_cast<uint8_t>(std::floor(
2211 std::get<double>(findOutLimit->second) + 0.5)));
2212 }
2213 else
2214 {
2215 count++;
2216 }
2217 }
2218 }
2219
2220 return ipmi::responseInvalidFieldRequest();
2221 }
2222 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002223 {
2224
2225 /*
2226 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002227 previous behavior didn't seem to prevent this, ignore the check for
2228 now.
James Feist5f957ca2019-03-14 15:33:55 -07002229
James Feistacc8a4e2019-04-02 14:23:57 -07002230 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002231 {
2232 phosphor::logging::log<phosphor::logging::level::ERR>(
2233 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002234 return IPMI_CC_REQ_DATA_LEN_INVALID;
2235 }
2236 */
2237 Value cfmLimit;
2238 Value cfmMaximum;
2239 try
2240 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002241 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002242 cfmLimitSettingPath, cfmLimitIface,
2243 "Limit");
2244 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002245 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002246 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2247 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002248 catch (const sdbusplus::exception_t& e)
James Feist5f957ca2019-03-14 15:33:55 -07002249 {
2250 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002251 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002252 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002253 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002254 }
2255
James Feistacc8a4e2019-04-02 14:23:57 -07002256 double cfmMax = std::get<double>(cfmMaximum);
2257 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002258
James Feistacc8a4e2019-04-02 14:23:57 -07002259 cfmLim = std::floor(cfmLim + 0.5);
2260 cfmMax = std::floor(cfmMax + 0.5);
2261 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2262 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002263
James Feistacc8a4e2019-04-02 14:23:57 -07002264 return ipmi::responseSuccess(
2265 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002266 }
James Feistacc8a4e2019-04-02 14:23:57 -07002267
James Feist5f957ca2019-03-14 15:33:55 -07002268 else
2269 {
2270 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002271 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002272 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002273 }
2274}
2275
Cheng C Yang773703a2019-08-15 09:41:11 +08002276using crConfigVariant =
2277 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2278
2279int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2280 const crConfigVariant& value,
2281 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2282{
2283 boost::system::error_code ec;
2284 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002285 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002286 "/xyz/openbmc_project/control/power_supply_redundancy",
2287 "org.freedesktop.DBus.Properties", "Set",
2288 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2289 if (ec)
2290 {
2291 phosphor::logging::log<phosphor::logging::level::ERR>(
2292 "Failed to set dbus property to cold redundancy");
2293 return -1;
2294 }
2295
2296 return 0;
2297}
2298
Kuiying Wange45333a2020-07-22 22:06:37 +08002299int getCRConfig(
2300 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2301 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2302 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002303{
2304 boost::system::error_code ec;
2305 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002306 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002307 "/xyz/openbmc_project/control/power_supply_redundancy",
2308 "org.freedesktop.DBus.Properties", "Get",
2309 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2310 if (ec)
2311 {
2312 phosphor::logging::log<phosphor::logging::level::ERR>(
2313 "Failed to get dbus property to cold redundancy");
2314 return -1;
2315 }
2316 return 0;
2317}
2318
2319uint8_t getPSUCount(void)
2320{
2321 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2322 ipmi::Value num;
2323 try
2324 {
2325 num = ipmi::getDbusProperty(
2326 *dbus, "xyz.openbmc_project.PSURedundancy",
2327 "/xyz/openbmc_project/control/power_supply_redundancy",
2328 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2329 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002330 catch (const sdbusplus::exception_t& e)
Cheng C Yang773703a2019-08-15 09:41:11 +08002331 {
2332 phosphor::logging::log<phosphor::logging::level::ERR>(
2333 "Failed to get PSUNumber property from dbus interface");
2334 return 0;
2335 }
2336 uint8_t* pNum = std::get_if<uint8_t>(&num);
2337 if (!pNum)
2338 {
2339 phosphor::logging::log<phosphor::logging::level::ERR>(
2340 "Error to get PSU Number");
2341 return 0;
2342 }
2343 return *pNum;
2344}
2345
2346bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2347{
2348 if (conf.size() < num)
2349 {
2350 phosphor::logging::log<phosphor::logging::level::ERR>(
2351 "Invalid PSU Ranking");
2352 return false;
2353 }
2354 std::set<uint8_t> confSet;
2355 for (uint8_t i = 0; i < num; i++)
2356 {
2357 if (conf[i] > num)
2358 {
2359 phosphor::logging::log<phosphor::logging::level::ERR>(
2360 "PSU Ranking is larger than current PSU number");
2361 return false;
2362 }
2363 confSet.emplace(conf[i]);
2364 }
2365
2366 if (confSet.size() != num)
2367 {
2368 phosphor::logging::log<phosphor::logging::level::ERR>(
2369 "duplicate PSU Ranking");
2370 return false;
2371 }
2372 return true;
2373}
2374
2375enum class crParameter
2376{
2377 crStatus = 0,
2378 crFeature = 1,
2379 rotationFeature = 2,
2380 rotationAlgo = 3,
2381 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002382 numOfPSU = 5,
2383 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002384};
2385
2386constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2387static const constexpr uint32_t oneDay = 0x15180;
2388static const constexpr uint32_t oneMonth = 0xf53700;
2389static const constexpr uint8_t userSpecific = 0x01;
2390static const constexpr uint8_t crSetCompleted = 0;
2391ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2392 uint8_t parameter,
2393 ipmi::message::Payload& payload)
2394{
2395 switch (static_cast<crParameter>(parameter))
2396 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002397 case crParameter::rotationFeature:
2398 {
2399 uint8_t param1;
2400 if (payload.unpack(param1) || !payload.fullyUnpacked())
2401 {
2402 return ipmi::responseReqDataLenInvalid();
2403 }
2404 // Rotation Enable can only be true or false
2405 if (param1 > 1)
2406 {
2407 return ipmi::responseInvalidFieldRequest();
2408 }
2409 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2410 {
2411 return ipmi::responseResponseError();
2412 }
2413 break;
2414 }
2415 case crParameter::rotationAlgo:
2416 {
2417 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2418 std::string algoName;
2419 uint8_t param1;
2420 if (payload.unpack(param1))
2421 {
2422 return ipmi::responseReqDataLenInvalid();
2423 }
2424 switch (param1)
2425 {
2426 case 0:
2427 algoName = "xyz.openbmc_project.Control."
2428 "PowerSupplyRedundancy.Algo.bmcSpecific";
2429 break;
2430 case 1:
2431 algoName = "xyz.openbmc_project.Control."
2432 "PowerSupplyRedundancy.Algo.userSpecific";
2433 break;
2434 default:
2435 return ipmi::responseInvalidFieldRequest();
2436 }
2437 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2438 {
2439 return ipmi::responseResponseError();
2440 }
2441
2442 uint8_t numberOfPSU = getPSUCount();
2443 if (!numberOfPSU)
2444 {
2445 return ipmi::responseResponseError();
2446 }
2447 std::vector<uint8_t> rankOrder;
2448
2449 if (param1 == userSpecific)
2450 {
2451 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2452 {
2453 ipmi::responseReqDataLenInvalid();
2454 }
Yong Li83315132019-10-23 17:42:24 +08002455 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002456 {
2457 return ipmi::responseReqDataLenInvalid();
2458 }
2459
2460 if (!validateCRAlgo(rankOrder, numberOfPSU))
2461 {
2462 return ipmi::responseInvalidFieldRequest();
2463 }
2464 }
2465 else
2466 {
2467 if (rankOrder.size() > 0)
2468 {
2469 return ipmi::responseReqDataLenInvalid();
2470 }
2471 for (uint8_t i = 1; i <= numberOfPSU; i++)
2472 {
2473 rankOrder.emplace_back(i);
2474 }
2475 }
2476 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2477 {
2478 return ipmi::responseResponseError();
2479 }
2480 break;
2481 }
2482 case crParameter::rotationPeriod:
2483 {
2484 // Minimum Rotation period is One day (86400 seconds) and Max
2485 // Rotation Period is 6 month (0xf53700 seconds)
2486 uint32_t period;
2487 if (payload.unpack(period) || !payload.fullyUnpacked())
2488 {
2489 return ipmi::responseReqDataLenInvalid();
2490 }
2491 if ((period < oneDay) || (period > oneMonth))
2492 {
2493 return ipmi::responseInvalidFieldRequest();
2494 }
2495 if (setCRConfig(ctx, "PeriodOfRotation", period))
2496 {
2497 return ipmi::responseResponseError();
2498 }
2499 break;
2500 }
2501 default:
2502 {
2503 return ipmi::response(ccParameterNotSupported);
2504 }
2505 }
2506
Cheng C Yang773703a2019-08-15 09:41:11 +08002507 return ipmi::responseSuccess(crSetCompleted);
2508}
2509
Yong Li83315132019-10-23 17:42:24 +08002510ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002511 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2512{
2513 crConfigVariant value;
2514 switch (static_cast<crParameter>(parameter))
2515 {
2516 case crParameter::crStatus:
2517 {
2518 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2519 {
2520 return ipmi::responseResponseError();
2521 }
2522 std::string* pStatus = std::get_if<std::string>(&value);
2523 if (!pStatus)
2524 {
2525 phosphor::logging::log<phosphor::logging::level::ERR>(
2526 "Error to get ColdRedundancyStatus property");
2527 return ipmi::responseResponseError();
2528 }
2529 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2530 auto status =
2531 server::PowerSupplyRedundancy::convertStatusFromString(
2532 *pStatus);
2533 switch (status)
2534 {
2535 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002536 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002537 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002538
2539 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002540 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002541 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002542 default:
2543 phosphor::logging::log<phosphor::logging::level::ERR>(
2544 "Error to get valid status");
2545 return ipmi::responseResponseError();
2546 }
2547 }
2548 case crParameter::crFeature:
2549 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002550 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002551 {
2552 return ipmi::responseResponseError();
2553 }
2554 bool* pResponse = std::get_if<bool>(&value);
2555 if (!pResponse)
2556 {
2557 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002558 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002559 return ipmi::responseResponseError();
2560 }
2561
Cheng C Yangf41e3342019-09-10 04:47:23 +08002562 return ipmi::responseSuccess(parameter,
2563 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002564 }
2565 case crParameter::rotationFeature:
2566 {
2567 if (getCRConfig(ctx, "RotationEnabled", value))
2568 {
2569 return ipmi::responseResponseError();
2570 }
2571 bool* pResponse = std::get_if<bool>(&value);
2572 if (!pResponse)
2573 {
2574 phosphor::logging::log<phosphor::logging::level::ERR>(
2575 "Error to get RotationEnabled property");
2576 return ipmi::responseResponseError();
2577 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002578 return ipmi::responseSuccess(parameter,
2579 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002580 }
2581 case crParameter::rotationAlgo:
2582 {
2583 if (getCRConfig(ctx, "RotationAlgorithm", value))
2584 {
2585 return ipmi::responseResponseError();
2586 }
2587
2588 std::string* pAlgo = std::get_if<std::string>(&value);
2589 if (!pAlgo)
2590 {
2591 phosphor::logging::log<phosphor::logging::level::ERR>(
2592 "Error to get RotationAlgorithm property");
2593 return ipmi::responseResponseError();
2594 }
Yong Li83315132019-10-23 17:42:24 +08002595 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002596 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2597 auto algo =
2598 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002599
Cheng C Yang773703a2019-08-15 09:41:11 +08002600 switch (algo)
2601 {
2602 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002603 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002604 break;
2605 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002606 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002607 break;
2608 default:
2609 phosphor::logging::log<phosphor::logging::level::ERR>(
2610 "Error to get valid algo");
2611 return ipmi::responseResponseError();
2612 }
2613
2614 if (getCRConfig(ctx, "RotationRankOrder", value))
2615 {
2616 return ipmi::responseResponseError();
2617 }
2618 std::vector<uint8_t>* pResponse =
2619 std::get_if<std::vector<uint8_t>>(&value);
2620 if (!pResponse)
2621 {
2622 phosphor::logging::log<phosphor::logging::level::ERR>(
2623 "Error to get RotationRankOrder property");
2624 return ipmi::responseResponseError();
2625 }
Yong Li83315132019-10-23 17:42:24 +08002626
Cheng C Yang773703a2019-08-15 09:41:11 +08002627 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002628 std::back_inserter(response));
2629
Cheng C Yangf41e3342019-09-10 04:47:23 +08002630 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002631 }
2632 case crParameter::rotationPeriod:
2633 {
2634 if (getCRConfig(ctx, "PeriodOfRotation", value))
2635 {
2636 return ipmi::responseResponseError();
2637 }
2638 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2639 if (!pResponse)
2640 {
2641 phosphor::logging::log<phosphor::logging::level::ERR>(
2642 "Error to get RotationAlgorithm property");
2643 return ipmi::responseResponseError();
2644 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002645 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002646 }
2647 case crParameter::numOfPSU:
2648 {
2649 uint8_t numberOfPSU = getPSUCount();
2650 if (!numberOfPSU)
2651 {
2652 return ipmi::responseResponseError();
2653 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002654 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002655 }
Yong Li19445ab2019-12-20 18:25:29 +08002656 case crParameter::rotationRankOrderEffective:
2657 {
2658 if (getCRConfig(ctx, "RotationRankOrder", value,
2659 "xyz.openbmc_project.PSURedundancy"))
2660 {
2661 return ipmi::responseResponseError();
2662 }
2663 std::vector<uint8_t>* pResponse =
2664 std::get_if<std::vector<uint8_t>>(&value);
2665 if (!pResponse)
2666 {
2667 phosphor::logging::log<phosphor::logging::level::ERR>(
2668 "Error to get effective RotationRankOrder property");
2669 return ipmi::responseResponseError();
2670 }
2671 return ipmi::responseSuccess(parameter, *pResponse);
2672 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002673 default:
2674 {
2675 return ipmi::response(ccParameterNotSupported);
2676 }
2677 }
2678}
2679
Zhu, Yungebe560b02019-04-21 21:19:21 -04002680ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2681 uint8_t faultState,
2682 uint8_t faultGroup,
2683 std::array<uint8_t, 8>& ledStateData)
2684{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002685 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2686 static const std::array<std::string, maxFaultType> faultNames = {
2687 "faultFan", "faultTemp", "faultPower",
2688 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002689
2690 constexpr uint8_t maxFaultSource = 0x4;
2691 constexpr uint8_t skipLEDs = 0xFF;
2692 constexpr uint8_t pinSize = 64;
2693 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002694 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002695
Zhikui Rence4e73f2019-12-06 13:59:47 -08002696 // same pin names need to be defined in dts file
2697 static const std::array<std::array<std::string, groupSize>, groupNum>
2698 faultLedPinNames = {{
2699 "LED_CPU1_CH1_DIMM1_FAULT",
2700 "LED_CPU1_CH1_DIMM2_FAULT",
2701 "LED_CPU1_CH2_DIMM1_FAULT",
2702 "LED_CPU1_CH2_DIMM2_FAULT",
2703 "LED_CPU1_CH3_DIMM1_FAULT",
2704 "LED_CPU1_CH3_DIMM2_FAULT",
2705 "LED_CPU1_CH4_DIMM1_FAULT",
2706 "LED_CPU1_CH4_DIMM2_FAULT",
2707 "LED_CPU1_CH5_DIMM1_FAULT",
2708 "LED_CPU1_CH5_DIMM2_FAULT",
2709 "LED_CPU1_CH6_DIMM1_FAULT",
2710 "LED_CPU1_CH6_DIMM2_FAULT",
2711 "",
2712 "",
2713 "",
2714 "", // end of group1
2715 "LED_CPU2_CH1_DIMM1_FAULT",
2716 "LED_CPU2_CH1_DIMM2_FAULT",
2717 "LED_CPU2_CH2_DIMM1_FAULT",
2718 "LED_CPU2_CH2_DIMM2_FAULT",
2719 "LED_CPU2_CH3_DIMM1_FAULT",
2720 "LED_CPU2_CH3_DIMM2_FAULT",
2721 "LED_CPU2_CH4_DIMM1_FAULT",
2722 "LED_CPU2_CH4_DIMM2_FAULT",
2723 "LED_CPU2_CH5_DIMM1_FAULT",
2724 "LED_CPU2_CH5_DIMM2_FAULT",
2725 "LED_CPU2_CH6_DIMM1_FAULT",
2726 "LED_CPU2_CH6_DIMM2_FAULT",
2727 "",
2728 "",
2729 "",
2730 "", // endof group2
2731 "LED_CPU3_CH1_DIMM1_FAULT",
2732 "LED_CPU3_CH1_DIMM2_FAULT",
2733 "LED_CPU3_CH2_DIMM1_FAULT",
2734 "LED_CPU3_CH2_DIMM2_FAULT",
2735 "LED_CPU3_CH3_DIMM1_FAULT",
2736 "LED_CPU3_CH3_DIMM2_FAULT",
2737 "LED_CPU3_CH4_DIMM1_FAULT",
2738 "LED_CPU3_CH4_DIMM2_FAULT",
2739 "LED_CPU3_CH5_DIMM1_FAULT",
2740 "LED_CPU3_CH5_DIMM2_FAULT",
2741 "LED_CPU3_CH6_DIMM1_FAULT",
2742 "LED_CPU3_CH6_DIMM2_FAULT",
2743 "",
2744 "",
2745 "",
2746 "", // end of group3
2747 "LED_CPU4_CH1_DIMM1_FAULT",
2748 "LED_CPU4_CH1_DIMM2_FAULT",
2749 "LED_CPU4_CH2_DIMM1_FAULT",
2750 "LED_CPU4_CH2_DIMM2_FAULT",
2751 "LED_CPU4_CH3_DIMM1_FAULT",
2752 "LED_CPU4_CH3_DIMM2_FAULT",
2753 "LED_CPU4_CH4_DIMM1_FAULT",
2754 "LED_CPU4_CH4_DIMM2_FAULT",
2755 "LED_CPU4_CH5_DIMM1_FAULT",
2756 "LED_CPU4_CH5_DIMM2_FAULT",
2757 "LED_CPU4_CH6_DIMM1_FAULT",
2758 "LED_CPU4_CH6_DIMM2_FAULT",
2759 "",
2760 "",
2761 "",
2762 "", // end of group4
2763 "LED_FAN1_FAULT",
2764 "LED_FAN2_FAULT",
2765 "LED_FAN3_FAULT",
2766 "LED_FAN4_FAULT",
2767 "LED_FAN5_FAULT",
2768 "LED_FAN6_FAULT",
2769 "LED_FAN7_FAULT",
2770 "LED_FAN8_FAULT",
2771 "",
2772 "",
2773 "",
2774 "",
2775 "",
2776 "",
2777 "",
2778 "" // end of group5
2779 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002780
Zhikui Rence4e73f2019-12-06 13:59:47 -08002781 // Validate the source, fault type --
2782 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2783 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2784 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2785 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2786 // definition differs based on fault type (Byte 2)
2787 // Type Fan=> Group: 0=FanGroupID, FF-not used
2788 // Byte 5-11 00h, not used
2789 // Byte12 FanLedState [7:0]-Fans 7:0
2790 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2791 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2792 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2793 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2794 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2795 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2796 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2797 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002798 if ((sourceId >= maxFaultSource) ||
2799 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2800 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2801 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2802 {
2803 return ipmi::responseParmOutOfRange();
2804 }
2805
Zhikui Rence4e73f2019-12-06 13:59:47 -08002806 size_t pinGroupOffset = 0;
2807 size_t pinGroupMax = pinSize / groupSize;
2808 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002809 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002810 pinGroupOffset = 4;
2811 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002812 }
2813
2814 switch (RemoteFaultType(faultType))
2815 {
2816 case (RemoteFaultType::fan):
2817 case (RemoteFaultType::memory):
2818 {
2819 if (faultGroup == skipLEDs)
2820 {
2821 return ipmi::responseSuccess();
2822 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002823 // calculate led state bit filed count, each byte has 8bits
2824 // the maximum bits will be 8 * 8 bits
2825 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002826
2827 // assemble ledState
2828 uint64_t ledState = 0;
2829 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002830 for (int i = 0; i < sizeof(ledStateData); i++)
2831 {
2832 ledState = (uint64_t)(ledState << 8);
2833 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2834 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002835 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002836
Zhikui Rence4e73f2019-12-06 13:59:47 -08002837 for (int group = 0; group < pinGroupMax; group++)
2838 {
2839 for (int i = 0; i < groupSize; i++)
2840 { // skip non-existing pins
2841 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2842 {
2843 continue;
2844 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002845
Zhikui Rence4e73f2019-12-06 13:59:47 -08002846 gpiod::line line = gpiod::find_line(
2847 faultLedPinNames[group + pinGroupOffset][i]);
2848 if (!line)
2849 {
2850 phosphor::logging::log<phosphor::logging::level::ERR>(
2851 "Not Find Led Gpio Device!",
2852 phosphor::logging::entry(
2853 "DEVICE=%s",
2854 faultLedPinNames[group + pinGroupOffset][i]
2855 .c_str()));
2856 hasError = true;
2857 continue;
2858 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002859
Zhikui Rence4e73f2019-12-06 13:59:47 -08002860 bool activeHigh =
2861 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2862 try
2863 {
2864 line.request(
2865 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2866 activeHigh
2867 ? 0
2868 : gpiod::line_request::FLAG_ACTIVE_LOW});
2869 line.set_value(ledStateBits[i + group * groupSize]);
2870 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002871 catch (const std::system_error&)
Zhikui Rence4e73f2019-12-06 13:59:47 -08002872 {
2873 phosphor::logging::log<phosphor::logging::level::ERR>(
2874 "Error write Led Gpio Device!",
2875 phosphor::logging::entry(
2876 "DEVICE=%s",
2877 faultLedPinNames[group + pinGroupOffset][i]
2878 .c_str()));
2879 hasError = true;
2880 continue;
2881 }
2882 } // for int i
2883 }
2884 if (hasError)
2885 {
2886 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002887 }
2888 break;
2889 }
2890 default:
2891 {
2892 // now only support two fault types
2893 return ipmi::responseParmOutOfRange();
2894 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002895 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002896 return ipmi::responseSuccess();
2897}
2898
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302899ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2900{
2901 uint8_t prodId = 0;
2902 try
2903 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002904 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302905 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002906 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302907 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2908 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002909 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302910 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2911 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302912 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2913 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05002914 catch (const std::exception& e)
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302915 {
2916 phosphor::logging::log<phosphor::logging::level::ERR>(
2917 "ipmiOEMReadBoardProductId: Product ID read failed!",
2918 phosphor::logging::entry("ERR=%s", e.what()));
2919 }
2920 return ipmi::responseSuccess(prodId);
2921}
2922
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302923/** @brief implements the get security mode command
2924 * @param ctx - ctx pointer
2925 *
2926 * @returns IPMI completion code with following data
2927 * - restriction mode value - As specified in
2928 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2929 * - special mode value - As specified in
2930 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2931 */
2932ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2933{
2934 namespace securityNameSpace =
2935 sdbusplus::xyz::openbmc_project::Control::Security::server;
2936 uint8_t restrictionModeValue = 0;
2937 uint8_t specialModeValue = 0;
2938
2939 boost::system::error_code ec;
2940 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002941 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302942 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2943 restricionModeProperty);
2944 if (ec)
2945 {
2946 phosphor::logging::log<phosphor::logging::level::ERR>(
2947 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2948 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2949 return ipmi::responseUnspecifiedError();
2950 }
2951 restrictionModeValue = static_cast<uint8_t>(
2952 securityNameSpace::RestrictionMode::convertModesFromString(
2953 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302954 auto varSpecialMode =
2955 ctx->bus->yield_method_call<std::variant<std::string>>(
2956 ctx->yield, ec, specialModeService, specialModeBasePath,
2957 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2958 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302959 if (ec)
2960 {
2961 phosphor::logging::log<phosphor::logging::level::ERR>(
2962 "ipmiGetSecurityMode: failed to get SpecialMode property",
2963 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2964 // fall through, let us not worry about SpecialMode property, which is
2965 // not required in user scenario
2966 }
2967 else
2968 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302969 specialModeValue = static_cast<uint8_t>(
2970 securityNameSpace::SpecialMode::convertModesFromString(
2971 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302972 }
2973 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2974}
2975
2976/** @brief implements the set security mode command
2977 * Command allows to upgrade the restriction mode and won't allow
2978 * to downgrade from system interface
2979 * @param ctx - ctx pointer
2980 * @param restrictionMode - restriction mode value to be set.
2981 *
2982 * @returns IPMI completion code
2983 */
2984ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302985 uint8_t restrictionMode,
2986 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302987{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302988#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2989 if (specialMode)
2990 {
2991 return ipmi::responseReqDataLenInvalid();
2992 }
2993#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302994 namespace securityNameSpace =
2995 sdbusplus::xyz::openbmc_project::Control::Security::server;
2996
2997 ChannelInfo chInfo;
2998 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2999 {
3000 phosphor::logging::log<phosphor::logging::level::ERR>(
3001 "ipmiSetSecurityMode: Failed to get Channel Info",
3002 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
3003 return ipmi::responseUnspecifiedError();
3004 }
3005 auto reqMode =
3006 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
3007
3008 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
3009 (reqMode >
3010 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
3011 {
3012 return ipmi::responseInvalidFieldRequest();
3013 }
3014
3015 boost::system::error_code ec;
3016 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07003017 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303018 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
3019 restricionModeProperty);
3020 if (ec)
3021 {
3022 phosphor::logging::log<phosphor::logging::level::ERR>(
3023 "ipmiSetSecurityMode: failed to get RestrictionMode property",
3024 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3025 return ipmi::responseUnspecifiedError();
3026 }
3027 auto currentRestrictionMode =
3028 securityNameSpace::RestrictionMode::convertModesFromString(
3029 std::get<std::string>(varRestrMode));
3030
3031 if (chInfo.mediumType !=
3032 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
3033 currentRestrictionMode > reqMode)
3034 {
3035 phosphor::logging::log<phosphor::logging::level::ERR>(
3036 "ipmiSetSecurityMode - Downgrading security mode not supported "
3037 "through system interface",
3038 phosphor::logging::entry(
3039 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
3040 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
3041 return ipmi::responseCommandNotAvailable();
3042 }
3043
3044 ec.clear();
3045 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07003046 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303047 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
3048 restricionModeProperty,
3049 static_cast<std::variant<std::string>>(
3050 securityNameSpace::convertForMessage(reqMode)));
3051
3052 if (ec)
3053 {
3054 phosphor::logging::log<phosphor::logging::level::ERR>(
3055 "ipmiSetSecurityMode: failed to set RestrictionMode property",
3056 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3057 return ipmi::responseUnspecifiedError();
3058 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303059
3060#ifdef BMC_VALIDATION_UNSECURE_FEATURE
3061 if (specialMode)
3062 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00003063 constexpr uint8_t mfgMode = 0x01;
3064 // Manufacturing mode is reserved. So can't enable this mode.
3065 if (specialMode.value() == mfgMode)
3066 {
3067 phosphor::logging::log<phosphor::logging::level::INFO>(
3068 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
3069 return ipmi::responseInvalidFieldRequest();
3070 }
3071
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05303072 ec.clear();
3073 ctx->bus->yield_method_call<>(
3074 ctx->yield, ec, specialModeService, specialModeBasePath,
3075 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
3076 specialModeProperty,
3077 static_cast<std::variant<std::string>>(
3078 securityNameSpace::convertForMessage(
3079 static_cast<securityNameSpace::SpecialMode::Modes>(
3080 specialMode.value()))));
3081
3082 if (ec)
3083 {
3084 phosphor::logging::log<phosphor::logging::level::ERR>(
3085 "ipmiSetSecurityMode: failed to set SpecialMode property",
3086 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
3087 return ipmi::responseUnspecifiedError();
3088 }
3089 }
3090#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303091 return ipmi::responseSuccess();
3092}
3093
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003094ipmi::RspType<uint8_t /* restore status */>
3095 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
3096{
3097 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
3098
3099 if (clr != expClr)
3100 {
3101 return ipmi::responseInvalidFieldRequest();
3102 }
3103 constexpr uint8_t cmdStatus = 0;
3104 constexpr uint8_t cmdDefaultRestore = 0xaa;
3105 constexpr uint8_t cmdFullRestore = 0xbb;
3106 constexpr uint8_t cmdFormat = 0xcc;
3107
3108 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
3109
3110 switch (cmd)
3111 {
3112 case cmdStatus:
3113 break;
3114 case cmdDefaultRestore:
3115 case cmdFullRestore:
3116 case cmdFormat:
3117 {
3118 // write file to rwfs root
3119 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
3120 std::ofstream restoreFile(restoreOpFname);
3121 if (!restoreFile)
3122 {
3123 return ipmi::responseUnspecifiedError();
3124 }
3125 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05303126
3127 phosphor::logging::log<phosphor::logging::level::WARNING>(
3128 "Restore to default will be performed on next BMC boot",
3129 phosphor::logging::entry("ACTION=0x%0X", cmd));
3130
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003131 break;
3132 }
3133 default:
3134 return ipmi::responseInvalidFieldRequest();
3135 }
3136
3137 constexpr uint8_t restorePending = 0;
3138 constexpr uint8_t restoreComplete = 1;
3139
3140 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
3141 ? restorePending
3142 : restoreComplete;
3143 return ipmi::responseSuccess(restoreStatus);
3144}
3145
Chen Yugang39736d52019-07-12 16:24:33 +08003146ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
3147{
3148 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003149 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003150
3151 try
3152 {
3153 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3154 std::string service =
3155 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
3156 Value variant =
3157 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
3158 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
3159
3160 switch (nmi::NMISource::convertBMCSourceSignalFromString(
3161 std::get<std::string>(variant)))
3162 {
3163 case nmi::NMISource::BMCSourceSignal::None:
3164 bmcSource = static_cast<uint8_t>(NmiSource::none);
3165 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003166 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
3167 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08003168 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003169 case nmi::NMISource::BMCSourceSignal::Watchdog:
3170 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08003171 break;
3172 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
3173 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
3174 break;
3175 case nmi::NMISource::BMCSourceSignal::MemoryError:
3176 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
3177 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003178 case nmi::NMISource::BMCSourceSignal::PciBusError:
3179 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08003180 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003181 case nmi::NMISource::BMCSourceSignal::PCH:
3182 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003183 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003184 case nmi::NMISource::BMCSourceSignal::Chipset:
3185 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003186 break;
3187 default:
3188 phosphor::logging::log<phosphor::logging::level::ERR>(
3189 "NMI source: invalid property!",
3190 phosphor::logging::entry(
3191 "PROP=%s", std::get<std::string>(variant).c_str()));
3192 return ipmi::responseResponseError();
3193 }
3194 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003195 catch (const sdbusplus::exception::exception& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003196 {
3197 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3198 return ipmi::responseResponseError();
3199 }
3200
3201 return ipmi::responseSuccess(bmcSource);
3202}
3203
3204ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3205{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003206 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003207
3208 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3209 nmi::NMISource::BMCSourceSignal::None;
3210
3211 switch (NmiSource(sourceId))
3212 {
3213 case NmiSource::none:
3214 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3215 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003216 case NmiSource::frontPanelButton:
3217 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003218 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003219 case NmiSource::watchdog:
3220 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003221 break;
3222 case NmiSource::chassisCmd:
3223 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3224 break;
3225 case NmiSource::memoryError:
3226 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3227 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003228 case NmiSource::pciBusError:
3229 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003230 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003231 case NmiSource::pch:
3232 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003233 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003234 case NmiSource::chipset:
3235 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003236 break;
3237 default:
3238 phosphor::logging::log<phosphor::logging::level::ERR>(
3239 "NMI source: invalid property!");
3240 return ipmi::responseResponseError();
3241 }
3242
3243 try
3244 {
3245 // keep NMI signal source
3246 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3247 std::string service =
3248 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003249 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3250 oemNmiBmcSourceObjPathProp,
3251 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003252 // set Enabled property to inform NMI source handling
3253 // to trigger a NMI_OUT BSOD.
3254 // if it's triggered by NMI source property changed,
3255 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3256 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3257 {
3258 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3259 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3260 static_cast<bool>(true));
3261 }
Chen Yugang39736d52019-07-12 16:24:33 +08003262 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003263 catch (const sdbusplus::exception_t& e)
Chen Yugang39736d52019-07-12 16:24:33 +08003264 {
3265 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3266 return ipmi::responseResponseError();
3267 }
3268
3269 return ipmi::responseSuccess();
3270}
3271
James Feist63efafa2019-07-24 12:39:21 -07003272namespace dimmOffset
3273{
3274constexpr const char* dimmPower = "DimmPower";
3275constexpr const char* staticCltt = "StaticCltt";
3276constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3277constexpr const char* offsetInterface =
3278 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3279constexpr const char* property = "DimmOffset";
3280
3281}; // namespace dimmOffset
3282
3283ipmi::RspType<>
3284 ipmiOEMSetDimmOffset(uint8_t type,
3285 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3286{
3287 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3288 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3289 {
3290 return ipmi::responseInvalidFieldRequest();
3291 }
3292
3293 if (data.empty())
3294 {
3295 return ipmi::responseInvalidFieldRequest();
3296 }
3297 nlohmann::json json;
3298
3299 std::ifstream jsonStream(dimmOffsetFile);
3300 if (jsonStream.good())
3301 {
3302 json = nlohmann::json::parse(jsonStream, nullptr, false);
3303 if (json.is_discarded())
3304 {
3305 json = nlohmann::json();
3306 }
3307 jsonStream.close();
3308 }
3309
3310 std::string typeName;
3311 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3312 {
3313 typeName = dimmOffset::dimmPower;
3314 }
3315 else
3316 {
3317 typeName = dimmOffset::staticCltt;
3318 }
3319
3320 nlohmann::json& field = json[typeName];
3321
3322 for (const auto& [index, value] : data)
3323 {
3324 field[index] = value;
3325 }
3326
3327 for (nlohmann::json& val : field)
3328 {
3329 if (val == nullptr)
3330 {
3331 val = static_cast<uint8_t>(0);
3332 }
3333 }
3334
3335 std::ofstream output(dimmOffsetFile);
3336 if (!output.good())
3337 {
3338 std::cerr << "Error writing json file\n";
3339 return ipmi::responseResponseError();
3340 }
3341
3342 output << json.dump(4);
3343
3344 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3345 {
3346 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3347
3348 std::variant<std::vector<uint8_t>> offsets =
3349 field.get<std::vector<uint8_t>>();
3350 auto call = bus->new_method_call(
3351 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3352 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3353 try
3354 {
3355 bus->call(call);
3356 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003357 catch (const sdbusplus::exception_t& e)
James Feist63efafa2019-07-24 12:39:21 -07003358 {
3359 phosphor::logging::log<phosphor::logging::level::ERR>(
3360 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3361 phosphor::logging::entry("ERR=%s", e.what()));
3362 return ipmi::responseResponseError();
3363 }
3364 }
3365
3366 return ipmi::responseSuccess();
3367}
3368
3369ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3370{
3371
3372 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3373 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3374 {
3375 return ipmi::responseInvalidFieldRequest();
3376 }
3377
3378 std::ifstream jsonStream(dimmOffsetFile);
3379
3380 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3381 if (json.is_discarded())
3382 {
3383 std::cerr << "File error in " << dimmOffsetFile << "\n";
3384 return ipmi::responseResponseError();
3385 }
3386
3387 std::string typeName;
3388 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3389 {
3390 typeName = dimmOffset::dimmPower;
3391 }
3392 else
3393 {
3394 typeName = dimmOffset::staticCltt;
3395 }
3396
3397 auto it = json.find(typeName);
3398 if (it == json.end())
3399 {
3400 return ipmi::responseInvalidFieldRequest();
3401 }
3402
3403 if (it->size() <= index)
3404 {
3405 return ipmi::responseInvalidFieldRequest();
3406 }
3407
3408 uint8_t resp = it->at(index).get<uint8_t>();
3409 return ipmi::responseSuccess(resp);
3410}
3411
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003412namespace boot_options
3413{
3414
3415using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3416using IpmiValue = uint8_t;
3417constexpr auto ipmiDefault = 0;
3418
3419std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3420 {0x01, Source::Sources::Network},
3421 {0x02, Source::Sources::Disk},
3422 {0x05, Source::Sources::ExternalMedia},
3423 {0x0f, Source::Sources::RemovableMedia},
3424 {ipmiDefault, Source::Sources::Default}};
3425
3426std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003427 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003428
3429std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3430 {Source::Sources::Network, 0x01},
3431 {Source::Sources::Disk, 0x02},
3432 {Source::Sources::ExternalMedia, 0x05},
3433 {Source::Sources::RemovableMedia, 0x0f},
3434 {Source::Sources::Default, ipmiDefault}};
3435
3436std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003437 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003438
3439static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3440static constexpr auto bootSourceIntf =
3441 "xyz.openbmc_project.Control.Boot.Source";
3442static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3443static constexpr auto persistentObjPath =
3444 "/xyz/openbmc_project/control/host0/boot";
3445static constexpr auto oneTimePath =
3446 "/xyz/openbmc_project/control/host0/boot/one_time";
3447static constexpr auto bootSourceProp = "BootSource";
3448static constexpr auto bootModeProp = "BootMode";
3449static constexpr auto oneTimeBootEnableProp = "Enabled";
3450static constexpr auto httpBootMode =
3451 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3452
3453enum class BootOptionParameter : size_t
3454{
3455 setInProgress = 0x0,
3456 bootFlags = 0x5,
3457};
3458static constexpr uint8_t setComplete = 0x0;
3459static constexpr uint8_t setInProgress = 0x1;
3460static uint8_t transferStatus = setComplete;
3461static constexpr uint8_t setParmVersion = 0x01;
3462static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3463static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3464static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3465static constexpr uint8_t httpBoot = 0xd;
3466static constexpr uint8_t bootSourceMask = 0x3c;
3467
3468} // namespace boot_options
3469
3470ipmi::RspType<uint8_t, // version
3471 uint8_t, // param
3472 uint8_t, // data0, dependent on parameter
3473 std::optional<uint8_t> // data1, dependent on parameter
3474 >
3475 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3476{
3477 using namespace boot_options;
3478 uint8_t bootOption = 0;
3479
3480 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3481 {
3482 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3483 std::nullopt);
3484 }
3485
3486 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3487 {
3488 phosphor::logging::log<phosphor::logging::level::ERR>(
3489 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003490 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003491 }
3492
3493 try
3494 {
3495 auto oneTimeEnabled = false;
3496 // read one time Enabled property
3497 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3498 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3499 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3500 enabledIntf, oneTimeBootEnableProp);
3501 oneTimeEnabled = std::get<bool>(variant);
3502
3503 // get BootSource and BootMode properties
3504 // according to oneTimeEnable
3505 auto bootObjPath = oneTimePath;
3506 if (oneTimeEnabled == false)
3507 {
3508 bootObjPath = persistentObjPath;
3509 }
3510
3511 service = getService(*dbus, bootModeIntf, bootObjPath);
3512 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3513 bootModeProp);
3514
3515 auto bootMode =
3516 Mode::convertModesFromString(std::get<std::string>(variant));
3517
3518 service = getService(*dbus, bootSourceIntf, bootObjPath);
3519 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3520 bootSourceProp);
3521
3522 if (std::get<std::string>(variant) == httpBootMode)
3523 {
3524 bootOption = httpBoot;
3525 }
3526 else
3527 {
3528 auto bootSource = Source::convertSourcesFromString(
3529 std::get<std::string>(variant));
3530 bootOption = sourceDbusToIpmi.at(bootSource);
3531 if (Source::Sources::Default == bootSource)
3532 {
3533 bootOption = modeDbusToIpmi.at(bootMode);
3534 }
3535 }
3536
3537 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3538 : setParmBootFlagsValidPermanent;
3539 bootOption <<= 2; // shift for responseconstexpr
3540 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3541 bootOption);
3542 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003543 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003544 {
3545 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3546 return ipmi::responseResponseError();
3547 }
3548}
3549
3550ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3551 std::optional<uint8_t> bootOption)
3552{
3553 using namespace boot_options;
3554 auto oneTimeEnabled = false;
3555
3556 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3557 {
3558 if (bootOption)
3559 {
3560 return ipmi::responseReqDataLenInvalid();
3561 }
3562
3563 if (transferStatus == setInProgress)
3564 {
3565 phosphor::logging::log<phosphor::logging::level::ERR>(
3566 "boot option set in progress!");
3567 return ipmi::responseResponseError();
3568 }
3569
3570 transferStatus = bootParam;
3571 return ipmi::responseSuccess();
3572 }
3573
3574 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3575 {
3576 phosphor::logging::log<phosphor::logging::level::ERR>(
3577 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003578 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003579 }
3580
3581 if (!bootOption)
3582 {
3583 return ipmi::responseReqDataLenInvalid();
3584 }
3585
3586 if (((bootOption.value() & bootSourceMask) >> 2) !=
3587 httpBoot) // not http boot, exit
3588 {
3589 phosphor::logging::log<phosphor::logging::level::ERR>(
3590 "wrong boot option parameter!");
3591 return ipmi::responseParmOutOfRange();
3592 }
3593
3594 try
3595 {
3596 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3597 setParmBootFlagsPermanent;
3598
3599 // read one time Enabled property
3600 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3601 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3602 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3603 enabledIntf, oneTimeBootEnableProp);
3604 oneTimeEnabled = std::get<bool>(variant);
3605
3606 /*
3607 * Check if the current boot setting is onetime or permanent, if the
3608 * request in the command is otherwise, then set the "Enabled"
3609 * property in one_time object path to 'True' to indicate onetime
3610 * and 'False' to indicate permanent.
3611 *
3612 * Once the onetime/permanent setting is applied, then the bootMode
3613 * and bootSource is updated for the corresponding object.
3614 */
3615 if (permanent == oneTimeEnabled)
3616 {
3617 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3618 oneTimeBootEnableProp, !permanent);
3619 }
3620
3621 // set BootSource and BootMode properties
3622 // according to oneTimeEnable or persistent
3623 auto bootObjPath = oneTimePath;
3624 if (oneTimeEnabled == false)
3625 {
3626 bootObjPath = persistentObjPath;
3627 }
3628 std::string bootMode =
3629 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3630 std::string bootSource = httpBootMode;
3631
3632 service = getService(*dbus, bootModeIntf, bootObjPath);
3633 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3634 bootMode);
3635
3636 service = getService(*dbus, bootSourceIntf, bootObjPath);
3637 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3638 bootSourceProp, bootSource);
3639 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -05003640 catch (const sdbusplus::exception_t& e)
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003641 {
3642 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3643 return ipmi::responseResponseError();
3644 }
3645
3646 return ipmi::responseSuccess();
3647}
3648
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003649using BasicVariantType =
3650 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3651 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3652 uint16_t, uint8_t, bool>;
3653using PropertyMapType =
3654 boost::container::flat_map<std::string, BasicVariantType>;
3655static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3656 "xyz.openbmc_project.Configuration.PSUPresence"};
3657int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3658 std::vector<uint64_t>& addrTable)
3659{
3660 boost::system::error_code ec;
3661 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3662 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3663 "/xyz/openbmc_project/object_mapper",
3664 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3665 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3666 if (ec)
3667 {
3668 phosphor::logging::log<phosphor::logging::level::ERR>(
3669 "Failed to set dbus property to cold redundancy");
3670 return -1;
3671 }
3672 for (const auto& object : subtree)
3673 {
3674 std::string pathName = object.first;
3675 for (const auto& serviceIface : object.second)
3676 {
3677 std::string serviceName = serviceIface.first;
3678
3679 ec.clear();
3680 PropertyMapType propMap =
3681 ctx->bus->yield_method_call<PropertyMapType>(
3682 ctx->yield, ec, serviceName, pathName,
3683 "org.freedesktop.DBus.Properties", "GetAll",
3684 "xyz.openbmc_project.Configuration.PSUPresence");
3685 if (ec)
3686 {
3687 phosphor::logging::log<phosphor::logging::level::ERR>(
3688 "Failed to set dbus property to cold redundancy");
3689 return -1;
3690 }
3691 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3692 auto psuAddress =
3693 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3694
3695 if (psuBus == nullptr || psuAddress == nullptr)
3696 {
3697 std::cerr << "error finding necessary "
3698 "entry in configuration\n";
3699 return -1;
3700 }
3701 bus = static_cast<uint8_t>(*psuBus);
3702 addrTable = *psuAddress;
3703 return 0;
3704 }
3705 }
3706 return -1;
3707}
3708
3709static const constexpr uint8_t addrOffset = 8;
3710static const constexpr uint8_t psuRevision = 0xd9;
3711static const constexpr uint8_t defaultPSUBus = 7;
3712// Second Minor, Primary Minor, Major
3713static const constexpr size_t verLen = 3;
3714ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3715{
3716 uint8_t bus = defaultPSUBus;
3717 std::vector<uint64_t> addrTable;
3718 std::vector<uint8_t> result;
3719 if (getPSUAddress(ctx, bus, addrTable))
3720 {
3721 std::cerr << "Failed to get PSU bus and address\n";
3722 return ipmi::responseResponseError();
3723 }
3724
3725 for (const auto& slaveAddr : addrTable)
3726 {
3727 std::vector<uint8_t> writeData = {psuRevision};
3728 std::vector<uint8_t> readBuf(verLen);
3729 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3730 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3731
3732 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3733 if (retI2C != ipmi::ccSuccess)
3734 {
3735 for (size_t idx = 0; idx < verLen; idx++)
3736 {
3737 result.emplace_back(0x00);
3738 }
3739 }
3740 else
3741 {
3742 for (const uint8_t& data : readBuf)
3743 {
3744 result.emplace_back(data);
3745 }
3746 }
3747 }
3748
3749 return ipmi::responseSuccess(result);
3750}
3751
srikanta mondal2030d7c2020-05-03 17:25:25 +00003752std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3753 const std::string& name)
3754{
3755 Value dbusValue = 0;
3756 std::string serviceName;
3757
3758 boost::system::error_code ec =
3759 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3760
3761 if (ec)
3762 {
3763 phosphor::logging::log<phosphor::logging::level::ERR>(
3764 "Failed to perform Multinode getService.");
3765 return std::nullopt;
3766 }
3767
3768 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3769 multiNodeIntf, name, dbusValue);
3770 if (ec)
3771 {
3772 phosphor::logging::log<phosphor::logging::level::ERR>(
3773 "Failed to perform Multinode get property");
3774 return std::nullopt;
3775 }
3776
3777 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3778 if (!multiNodeVal)
3779 {
3780 phosphor::logging::log<phosphor::logging::level::ERR>(
3781 "getMultiNodeInfoPresence: error to get multinode");
3782 return std::nullopt;
3783 }
3784 return *multiNodeVal;
3785}
3786
3787/** @brief implements OEM get reading command
3788 * @param domain ID
3789 * @param reading Type
3790 * - 00h = platform Power Consumption
3791 * - 01h = inlet Air Temp
3792 * - 02h = icc_TDC from PECI
3793 * @param reserved, write as 0000h
3794 *
3795 * @returns IPMI completion code plus response data
3796 * - response
3797 * - domain ID
3798 * - reading Type
3799 * - 00h = platform Power Consumption
3800 * - 01h = inlet Air Temp
3801 * - 02h = icc_TDC from PECI
3802 * - reading
3803 */
3804ipmi::RspType<uint4_t, // domain ID
3805 uint4_t, // reading Type
3806 uint16_t // reading Value
3807 >
3808 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3809 uint4_t readingType, uint16_t reserved)
3810{
3811 constexpr uint8_t platformPower = 0;
3812 constexpr uint8_t inletAirTemp = 1;
3813 constexpr uint8_t iccTdc = 2;
3814
3815 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3816 {
3817 return ipmi::responseInvalidFieldRequest();
3818 }
3819
3820 // This command should run only from multi-node product.
3821 // For all other platforms this command will return invalid.
3822
3823 std::optional<uint8_t> nodeInfo =
3824 getMultiNodeInfoPresence(ctx, "NodePresence");
3825 if (!nodeInfo || !*nodeInfo)
3826 {
3827 return ipmi::responseInvalidCommand();
3828 }
3829
3830 uint16_t oemReadingValue = 0;
3831 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3832 {
3833 double value = 0;
3834 boost::system::error_code ec = ipmi::getDbusProperty(
3835 ctx, "xyz.openbmc_project.HwmonTempSensor",
3836 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3837 "xyz.openbmc_project.Sensor.Value", "Value", value);
3838 if (ec)
3839 {
3840 phosphor::logging::log<phosphor::logging::level::ERR>(
3841 "Failed to get BMC Get OEM temperature",
3842 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3843 return ipmi::responseUnspecifiedError();
3844 }
3845 // Take the Inlet temperature
3846 oemReadingValue = static_cast<uint16_t>(value);
3847 }
3848 else
3849 {
3850 phosphor::logging::log<phosphor::logging::level::ERR>(
3851 "Currently Get OEM Reading support only for Inlet Air Temp");
3852 return ipmi::responseParmOutOfRange();
3853 }
3854 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3855}
3856
AppaRao Puli28972062019-11-11 02:04:45 +05303857/** @brief implements the maximum size of
3858 * bridgeable messages used between KCS and
3859 * IPMB interfacesget security mode command.
3860 *
3861 * @returns IPMI completion code with following data
3862 * - KCS Buffer Size (In multiples of four bytes)
3863 * - IPMB Buffer Size (In multiples of four bytes)
3864 **/
3865ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3866{
3867 // for now this is hard coded; really this number is dependent on
3868 // the BMC kcs driver as well as the host kcs driver....
3869 // we can't know the latter.
3870 uint8_t kcsMaxBufferSize = 63 / 4;
3871 uint8_t ipmbMaxBufferSize = 128 / 4;
3872
3873 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3874}
3875
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00003876ipmi::RspType<std::vector<uint8_t>>
3877 ipmiOEMReadPFRMailbox(ipmi::Context::ptr& ctx, const uint8_t readRegister,
3878 const uint8_t numOfBytes, uint8_t registerIdentifier)
3879{
3880 if (!ipmi::mailbox::i2cConfigLoaded)
3881 {
3882
3883 phosphor::logging::log<phosphor::logging::level::ERR>(
3884 "Calling PFR Load Configuration Function to Get I2C Bus and Slave "
3885 "Address ");
3886
3887 ipmi::mailbox::loadPfrConfig(ctx, ipmi::mailbox::i2cConfigLoaded);
3888 }
3889
3890 if (!numOfBytes && !readRegister)
3891 {
3892 phosphor::logging::log<phosphor::logging::level::ERR>(
3893 "OEM IPMI command: Read & write count are 0 which is invalid ");
3894 return ipmi::responseInvalidFieldRequest();
3895 }
3896
3897 switch (registerIdentifier)
3898 {
3899 case ipmi::mailbox::registerType::fifoReadRegister:
3900 {
3901 // Check if readRegister is an FIFO read register
3902 if (registerIdentifier == 1)
3903 {
3904 if (ipmi::mailbox::readFifoReg.find(readRegister) ==
3905 ipmi::mailbox::readFifoReg.end())
3906 {
3907 phosphor::logging::log<phosphor::logging::level::ERR>(
3908 "OEM IPMI command: Register is not a Read FIFO ");
3909 return ipmi::responseInvalidFieldRequest();
3910 }
3911
3912 phosphor::logging::log<phosphor::logging::level::ERR>(
3913 "OEM IPMI command: Register is a Read FIFO ");
3914
3915 ipmi::mailbox::writefifo(ipmi::mailbox::provisioningCommand,
3916 readRegister);
3917 ipmi::mailbox::writefifo(ipmi::mailbox::triggerCommand,
3918 ipmi::mailbox::flushRead);
3919
3920 std::vector<uint8_t> writeData = {ipmi::mailbox::readFifo};
3921 std::vector<uint8_t> readBuf(1);
3922 std::vector<uint8_t> result;
3923
3924 for (int i = 0; i < numOfBytes; i++)
3925 {
3926
3927 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
3928 ipmi::mailbox::slaveAddr,
3929 writeData, readBuf);
3930 if (ret != ipmi::ccSuccess)
3931 {
3932 return ipmi::response(ret);
3933 }
3934
3935 else
3936 {
3937 for (const uint8_t& data : readBuf)
3938 {
3939 result.emplace_back(data);
3940 }
3941 }
3942 }
3943
3944 return ipmi::responseSuccess(result);
3945 }
3946 }
3947
3948 case ipmi::mailbox::registerType::singleByteRegister:
3949 {
3950 phosphor::logging::log<phosphor::logging::level::ERR>(
3951 "OEM IPMI command: Register is a Single Byte Register ");
3952
3953 std::vector<uint8_t> writeData = {readRegister};
3954 std::vector<uint8_t> readBuf(numOfBytes);
3955
3956 ipmi::Cc ret = ipmi::i2cWriteRead(ipmi::mailbox::i2cBus,
3957 ipmi::mailbox::slaveAddr,
3958 writeData, readBuf);
3959 if (ret != ipmi::ccSuccess)
3960 {
3961 return ipmi::response(ret);
3962 }
3963 return ipmi::responseSuccess(readBuf);
3964 }
3965
3966 default:
3967 {
3968
3969 phosphor::logging::log<phosphor::logging::level::ERR>(
3970 "OEM IPMI command: Register identifier is not valid.It should "
3971 "be 0 "
3972 "for Single Byte Register and 1 for FIFO Read Register");
3973
3974 return ipmi::responseInvalidFieldRequest();
3975 }
3976 }
3977}
3978
Jason M. Bills64796042018-10-03 16:51:55 -07003979static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003980{
3981 phosphor::logging::log<phosphor::logging::level::INFO>(
3982 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003983 ipmiPrintAndRegister(intel::netFnGeneral,
3984 intel::general::cmdGetChassisIdentifier, NULL,
3985 ipmiOEMGetChassisIdentifier,
3986 PRIVILEGE_USER); // get chassis identifier
3987
3988 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3989 NULL, ipmiOEMSetSystemGUID,
3990 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003991
3992 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003993 registerHandler(prioOemBase, intel::netFnGeneral,
3994 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3995 ipmiOEMDisableBMCSystemReset);
3996
Jason M. Billsb02bf092019-08-15 13:01:56 -07003997 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003998 registerHandler(prioOemBase, intel::netFnGeneral,
3999 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
4000 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07004001
Vernon Mauery98bbf692019-09-16 11:14:59 -07004002 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
4003 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004004
Chen Yugang7a04f3a2019-10-08 11:12:35 +08004005 registerHandler(prioOemBase, intel::netFnGeneral,
4006 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
4007 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08004008
Vernon Mauery98bbf692019-09-16 11:14:59 -07004009 ipmiPrintAndRegister(intel::netFnGeneral,
4010 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
4011 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304012
Vernon Mauery98bbf692019-09-16 11:14:59 -07004013 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4014 intel::general::cmdSendEmbeddedFWUpdStatus,
4015 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05304016
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05304017 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
4018 Privilege::Admin, ipmiOEMSlotIpmb);
4019
Vernon Mauery98bbf692019-09-16 11:14:59 -07004020 ipmiPrintAndRegister(intel::netFnGeneral,
4021 intel::general::cmdSetPowerRestoreDelay, NULL,
4022 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
4023
4024 ipmiPrintAndRegister(intel::netFnGeneral,
4025 intel::general::cmdGetPowerRestoreDelay, NULL,
4026 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
4027
4028 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4029 intel::general::cmdSetOEMUser2Activation,
4030 Privilege::Callback, ipmiOEMSetUser2Activation);
4031
4032 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4033 intel::general::cmdSetSpecialUserPassword,
4034 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05304035
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004036 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004037 registerHandler(prioOemBase, intel::netFnGeneral,
4038 intel::general::cmdGetProcessorErrConfig, Privilege::User,
4039 ipmiOEMGetProcessorErrConfig);
4040
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004041 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07004042 registerHandler(prioOemBase, intel::netFnGeneral,
4043 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
4044 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07004045
Vernon Mauery98bbf692019-09-16 11:14:59 -07004046 ipmiPrintAndRegister(intel::netFnGeneral,
4047 intel::general::cmdSetShutdownPolicy, NULL,
4048 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004049
Vernon Mauery98bbf692019-09-16 11:14:59 -07004050 ipmiPrintAndRegister(intel::netFnGeneral,
4051 intel::general::cmdGetShutdownPolicy, NULL,
4052 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08004053
anil kumar appanaf945eee2019-09-25 23:29:11 +00004054 registerHandler(prioOemBase, intel::netFnGeneral,
4055 intel::general::cmdSetFanConfig, Privilege::User,
4056 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08004057
Vernon Mauery98bbf692019-09-16 11:14:59 -07004058 registerHandler(prioOemBase, intel::netFnGeneral,
4059 intel::general::cmdGetFanConfig, Privilege::User,
4060 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07004061
Vernon Mauery98bbf692019-09-16 11:14:59 -07004062 registerHandler(prioOemBase, intel::netFnGeneral,
4063 intel::general::cmdGetFanSpeedOffset, Privilege::User,
4064 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004065
Vernon Mauery98bbf692019-09-16 11:14:59 -07004066 registerHandler(prioOemBase, intel::netFnGeneral,
4067 intel::general::cmdSetFanSpeedOffset, Privilege::User,
4068 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07004069
Vernon Mauery98bbf692019-09-16 11:14:59 -07004070 registerHandler(prioOemBase, intel::netFnGeneral,
4071 intel::general::cmdSetFscParameter, Privilege::User,
4072 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07004073
Vernon Mauery98bbf692019-09-16 11:14:59 -07004074 registerHandler(prioOemBase, intel::netFnGeneral,
4075 intel::general::cmdGetFscParameter, Privilege::User,
4076 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05304077
Vernon Mauery98bbf692019-09-16 11:14:59 -07004078 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
4079 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
4080 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08004081
Vernon Mauery98bbf692019-09-16 11:14:59 -07004082 registerHandler(prioOemBase, intel::netFnGeneral,
4083 intel::general::cmdGetNmiStatus, Privilege::User,
4084 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08004085
Vernon Mauery98bbf692019-09-16 11:14:59 -07004086 registerHandler(prioOemBase, intel::netFnGeneral,
4087 intel::general::cmdSetNmiStatus, Privilege::Operator,
4088 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004089
Vernon Mauery98bbf692019-09-16 11:14:59 -07004090 registerHandler(prioOemBase, intel::netFnGeneral,
4091 intel::general::cmdGetEfiBootOptions, Privilege::User,
4092 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08004093
Vernon Mauery98bbf692019-09-16 11:14:59 -07004094 registerHandler(prioOemBase, intel::netFnGeneral,
4095 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
4096 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304097
Vernon Mauery98bbf692019-09-16 11:14:59 -07004098 registerHandler(prioOemBase, intel::netFnGeneral,
4099 intel::general::cmdGetSecurityMode, Privilege::User,
4100 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05304101
Vernon Mauery98bbf692019-09-16 11:14:59 -07004102 registerHandler(prioOemBase, intel::netFnGeneral,
4103 intel::general::cmdSetSecurityMode, Privilege::Admin,
4104 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004105
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00004106 registerHandler(prioOemBase, intel::netFnGeneral,
4107 intel::general::cmdGetLEDStatus, Privilege::Admin,
4108 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08004109
Vernon Mauery98bbf692019-09-16 11:14:59 -07004110 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
4111 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
4112 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
4113
4114 registerHandler(prioOemBase, intel::netFnGeneral,
4115 intel::general::cmdSetFaultIndication, Privilege::Operator,
4116 ipmiOEMSetFaultIndication);
4117
4118 registerHandler(prioOemBase, intel::netFnGeneral,
4119 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
4120 ipmiOEMSetCRConfig);
4121
4122 registerHandler(prioOemBase, intel::netFnGeneral,
4123 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
4124 ipmiOEMGetCRConfig);
4125
4126 registerHandler(prioOemBase, intel::netFnGeneral,
4127 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07004128 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07004129
Vernon Mauery98bbf692019-09-16 11:14:59 -07004130 registerHandler(prioOemBase, intel::netFnGeneral,
4131 intel::general::cmdSetDimmOffset, Privilege::Operator,
4132 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07004133
Vernon Mauery98bbf692019-09-16 11:14:59 -07004134 registerHandler(prioOemBase, intel::netFnGeneral,
4135 intel::general::cmdGetDimmOffset, Privilege::Operator,
4136 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08004137
Cheng C Yang4e6ee152019-09-25 10:27:44 +08004138 registerHandler(prioOemBase, intel::netFnGeneral,
4139 intel::general::cmdGetPSUVersion, Privilege::User,
4140 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05304141
4142 registerHandler(prioOemBase, intel::netFnGeneral,
4143 intel::general::cmdGetBufferSize, Privilege::User,
4144 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00004145
4146 registerHandler(prioOemBase, intel::netFnGeneral,
4147 intel::general::cmdOEMGetReading, Privilege::User,
4148 ipmiOEMGetReading);
Ankita Vilas Gawadea1650382022-01-08 10:30:40 +00004149
4150 registerHandler(prioOemBase, intel::netFnApp, intel::app::cmdPFRMailboxRead,
4151 Privilege::Admin, ipmiOEMReadPFRMailbox);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08004152}
4153
4154} // namespace ipmi