blob: 9fb4892503a59396ae46540d9d81a0db2ecb24e6 [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>
49#include <string>
50#include <variant>
51#include <vector>
52
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080053namespace ipmi
54{
Jason M. Bills64796042018-10-03 16:51:55 -070055static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070056
Jason M. Bills64796042018-10-03 16:51:55 -070057static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080058
Suryakanth Sekard509eb92018-11-15 17:44:11 +053059static constexpr auto ethernetIntf =
60 "xyz.openbmc_project.Network.EthernetInterface";
61static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
62static constexpr auto networkService = "xyz.openbmc_project.Network";
63static constexpr auto networkRoot = "/xyz/openbmc_project/network";
64
Chen Yugang97cf96e2019-11-01 08:55:11 +080065static constexpr const char* oemNmiSourceIntf =
66 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080067static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080068 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080069static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
70static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
71
James Feist63efafa2019-07-24 12:39:21 -070072static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
srikanta mondal2030d7c2020-05-03 17:25:25 +000073static constexpr const char* multiNodeObjPath =
74 "/xyz/openbmc_project/MultiNode/Status";
75static constexpr const char* multiNodeIntf =
76 "xyz.openbmc_project.Chassis.MultiNode";
James Feist63efafa2019-07-24 12:39:21 -070077
Chen Yugang39736d52019-07-12 16:24:33 +080078enum class NmiSource : uint8_t
79{
80 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080081 frontPanelButton = 1,
82 watchdog = 2,
83 chassisCmd = 3,
84 memoryError = 4,
85 pciBusError = 5,
86 pch = 6,
87 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080088};
89
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053090enum class SpecialUserIndex : uint8_t
91{
92 rootUser = 0,
93 atScaleDebugUser = 1
94};
95
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053096static constexpr const char* restricionModeService =
97 "xyz.openbmc_project.RestrictionMode.Manager";
98static constexpr const char* restricionModeBasePath =
99 "/xyz/openbmc_project/control/security/restriction_mode";
100static constexpr const char* restricionModeIntf =
101 "xyz.openbmc_project.Control.Security.RestrictionMode";
102static constexpr const char* restricionModeProperty = "RestrictionMode";
103
104static constexpr const char* specialModeService =
105 "xyz.openbmc_project.SpecialMode";
106static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530107 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530108static constexpr const char* specialModeIntf =
109 "xyz.openbmc_project.Security.SpecialMode";
110static constexpr const char* specialModeProperty = "SpecialMode";
111
112static constexpr const char* dBusPropertyIntf =
113 "org.freedesktop.DBus.Properties";
114static constexpr const char* dBusPropertyGetMethod = "Get";
115static constexpr const char* dBusPropertySetMethod = "Set";
116
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800117// return code: 0 successful
118int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
119{
120 std::string objpath = "/xyz/openbmc_project/FruDevice";
121 std::string intf = "xyz.openbmc_project.FruDeviceManager";
122 std::string service = getService(bus, intf, objpath);
123 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
124 if (valueTree.empty())
125 {
126 phosphor::logging::log<phosphor::logging::level::ERR>(
127 "No object implements interface",
128 phosphor::logging::entry("INTF=%s", intf.c_str()));
129 return -1;
130 }
131
Jason M. Bills64796042018-10-03 16:51:55 -0700132 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800133 {
134 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
135 if (interface == item.second.end())
136 {
137 continue;
138 }
139
140 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
141 if (property == interface->second.end())
142 {
143 continue;
144 }
145
146 try
147 {
148 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700149 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700150 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800151 {
152 phosphor::logging::log<phosphor::logging::level::ERR>(
153 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154 return -1;
155 }
Jason M. Bills64796042018-10-03 16:51:55 -0700156 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800157 return 0;
158 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700159 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800160 {
Jason M. Bills64796042018-10-03 16:51:55 -0700161 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162 return -1;
163 }
164 }
165 return -1;
166}
Jason M. Bills64796042018-10-03 16:51:55 -0700167
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800168// Returns the Chassis Identifier (serial #)
169ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
170 ipmi_request_t request,
171 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700172 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800173 ipmi_context_t context)
174{
175 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700176 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 {
Jason M. Bills64796042018-10-03 16:51:55 -0700178 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 return IPMI_CC_REQ_DATA_LEN_INVALID;
180 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700181 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
182 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 {
Jason M. Bills64796042018-10-03 16:51:55 -0700184 *dataLen = serial.size(); // length will never exceed response length
185 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800186 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700187 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800188 return IPMI_CC_OK;
189 }
Jason M. Bills64796042018-10-03 16:51:55 -0700190 *dataLen = 0;
191 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192}
193
194ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195 ipmi_request_t request,
196 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700197 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800198{
199 static constexpr size_t safeBufferLength = 50;
200 char buf[safeBufferLength] = {0};
201 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
202
Jason M. Bills64796042018-10-03 16:51:55 -0700203 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800204 {
Jason M. Bills64796042018-10-03 16:51:55 -0700205 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800206 return IPMI_CC_REQ_DATA_LEN_INVALID;
207 }
208
Jason M. Bills64796042018-10-03 16:51:55 -0700209 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800210
211 snprintf(
212 buf, safeBufferLength,
213 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
214 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
215 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
216 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
217 Data->node3, Data->node2, Data->node1);
218 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
219 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800220
221 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
222 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700223 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
224 std::string service = getService(*dbus, intf, objpath);
225 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800226 return IPMI_CC_OK;
227}
228
Jason M. Billsb02bf092019-08-15 13:01:56 -0700229ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
230 uint7_t reserved1)
231{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000232 if (reserved1)
233 {
234 return ipmi::responseInvalidFieldRequest();
235 }
236
Jason M. Billsb02bf092019-08-15 13:01:56 -0700237 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
238
239 try
240 {
241 auto service =
242 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
243 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
244 bmcResetDisablesIntf, "ResetOnSMI",
245 !disableResetOnSMI);
246 }
247 catch (std::exception& e)
248 {
249 phosphor::logging::log<phosphor::logging::level::ERR>(
250 "Failed to set BMC reset disables",
251 phosphor::logging::entry("EXCEPTION=%s", e.what()));
252 return ipmi::responseUnspecifiedError();
253 }
254
255 return ipmi::responseSuccess();
256}
257
258ipmi::RspType<bool, // disableResetOnSMI
259 uint7_t // reserved
260 >
261 ipmiOEMGetBMCResetDisables()
262{
263 bool disableResetOnSMI = true;
264
265 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
266 try
267 {
268 auto service =
269 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
270 Value variant =
271 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
272 bmcResetDisablesIntf, "ResetOnSMI");
273 disableResetOnSMI = !std::get<bool>(variant);
274 }
275 catch (std::exception& e)
276 {
277 phosphor::logging::log<phosphor::logging::level::ERR>(
278 "Failed to get BMC reset disables",
279 phosphor::logging::entry("EXCEPTION=%s", e.what()));
280 return ipmi::responseUnspecifiedError();
281 }
282
283 return ipmi::responseSuccess(disableResetOnSMI, 0);
284}
285
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800286ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
287 ipmi_request_t request, ipmi_response_t response,
288 ipmi_data_len_t dataLen, ipmi_context_t context)
289{
290 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
291
Jason M. Bills64796042018-10-03 16:51:55 -0700292 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800294 *dataLen = 0;
295 return IPMI_CC_REQ_DATA_LEN_INVALID;
296 }
Jason M. Bills64796042018-10-03 16:51:55 -0700297 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000298 for (auto idChar : idString)
299 {
300 if (!std::isprint(static_cast<unsigned char>(idChar)))
301 {
302 phosphor::logging::log<phosphor::logging::level::ERR>(
303 "BIOS ID contains non printable character");
304 return IPMI_CC_INVALID_FIELD_REQUEST;
305 }
306 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307
Vernon Mauery15419dd2019-05-24 09:40:30 -0700308 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000309 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
310 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800311 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800312 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
313 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700314 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 *dataLen = 1;
316 return IPMI_CC_OK;
317}
318
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530319bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
320 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800321{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800322 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530323 std::string bmcVersion;
324 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800325 {
326 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800327 }
328
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530329 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800330 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800331 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800332 MetaRevision revision = rev.value();
333 bmcMajor = revision.major;
334
335 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
336 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
337 }
338
339 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530340 std::string meVersion;
341 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800342 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800343 return false;
344 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530345 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
346 constexpr size_t matchedPhosphor = 6;
347 std::smatch results;
348 if (std::regex_match(meVersion, results, pattern1))
349 {
350 if (results.size() == matchedPhosphor)
351 {
352 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
Jayaprakash Mutyalad0657022021-08-26 21:18:08 +0000353 meMinor = static_cast<uint8_t>(std::stoi(results[2]) << 4 |
354 std::stoi(results[3]));
AppaRao Puli32825a22020-01-17 15:52:41 +0530355 }
356 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800357 return true;
358}
359
360ipmi::RspType<
361 std::variant<std::string,
362 std::tuple<uint8_t, std::array<uint8_t, 2>,
363 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
364 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
365 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530366 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
367 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530368 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800369{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800370 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
371 {
372 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800373 }
374
375 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800376 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800377 {
378 case OEMDevEntityType::biosId:
379 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530380 // Byte 2&3, Only used with selecting BIOS
381 if (!countToRead || !offset)
382 {
383 return ipmi::responseReqDataLenInvalid();
384 }
385
Vernon Mauery15419dd2019-05-24 09:40:30 -0700386 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800387 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000388 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800389 try
390 {
Yong Li2742b852019-12-16 14:55:11 +0800391 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000392 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800393 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700394 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530395 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800396 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800397 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800398 }
Jason M. Bills64796042018-10-03 16:51:55 -0700399 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530400 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700401 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530402 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700403 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800404 else
405 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530406 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800407 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800408
409 std::string readBuf = {0};
410 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530411 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800412 (readBuf.begin()));
413 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800414 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700415 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800416 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800417 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800418 }
419 }
420 break;
421
422 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800423 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530424 // Byte 2&3, Only used with selecting BIOS
425 if (countToRead || offset)
426 {
427 return ipmi::responseReqDataLenInvalid();
428 }
429
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800430 constexpr const size_t verLen = 2;
431 constexpr const size_t verTotalLen = 10;
432 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
433 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
434 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
435 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
436 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
437 // data0/1: BMC version number; data6/7: ME version number
438 // the others: HSC0/1/2 version number, not avaible.
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530439 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800440 {
441 return ipmi::responseUnspecifiedError();
442 }
443 return ipmi::responseSuccess(
444 std::tuple<
445 uint8_t, std::array<uint8_t, verLen>,
446 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
447 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
448 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
449 }
450 break;
451
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800452 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800453 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530454 // Byte 2&3, Only used with selecting BIOS
455 if (countToRead || offset)
456 {
457 return ipmi::responseReqDataLenInvalid();
458 }
459
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800460 constexpr const size_t sdrLen = 2;
461 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
462 return ipmi::responseSuccess(
463 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
464 readBuf});
465 }
466 break;
467
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800468 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800469 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800470 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800471}
472
473ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
474 ipmi_request_t request, ipmi_response_t response,
475 ipmi_data_len_t dataLen, ipmi_context_t context)
476{
477 if (*dataLen != 0)
478 {
Jason M. Bills64796042018-10-03 16:51:55 -0700479 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800480 return IPMI_CC_REQ_DATA_LEN_INVALID;
481 }
482
483 *dataLen = 1;
484 uint8_t* res = reinterpret_cast<uint8_t*>(response);
485 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
486 // AIC is available so that BIOS will not timeout repeatly which leads to
487 // slow booting.
488 *res = 0; // Byte1=Count of SlotPosition/FruID records.
489 return IPMI_CC_OK;
490}
491
Jason M. Bills64796042018-10-03 16:51:55 -0700492ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
493 ipmi_request_t request,
494 ipmi_response_t response,
495 ipmi_data_len_t dataLen,
496 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800497{
Jason M. Bills64796042018-10-03 16:51:55 -0700498 GetPowerRestoreDelayRes* resp =
499 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
500
501 if (*dataLen != 0)
502 {
503 *dataLen = 0;
504 return IPMI_CC_REQ_DATA_LEN_INVALID;
505 }
506
Vernon Mauery15419dd2019-05-24 09:40:30 -0700507 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700508 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700509 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700510 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700511 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700512 powerRestoreDelayIntf, powerRestoreDelayProp);
513
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700514 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700515 resp->byteLSB = delay;
516 resp->byteMSB = delay >> 8;
517
518 *dataLen = sizeof(GetPowerRestoreDelayRes);
519
520 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800521}
522
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800523static uint8_t bcdToDec(uint8_t val)
524{
525 return ((val / 16 * 10) + (val % 16));
526}
527
528// Allows an update utility or system BIOS to send the status of an embedded
529// firmware update attempt to the BMC. After received, BMC will create a logging
530// record.
531ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
532 uint8_t majorRevision,
533 uint8_t minorRevision,
534 uint32_t auxInfo)
535{
536 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700537 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800538 target = (target & selEvtTargetMask) >> selEvtTargetShift;
539
540 /* make sure the status is 0, 1, or 2 as per the spec */
541 if (status > 2)
542 {
543 return ipmi::response(ipmi::ccInvalidFieldRequest);
544 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700545 /* make sure the target is 0, 1, 2, or 4 as per the spec */
546 if (target > 4 || target == 3)
547 {
548 return ipmi::response(ipmi::ccInvalidFieldRequest);
549 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800550 /*orignal OEM command is to record OEM SEL.
551 But openbmc does not support OEM SEL, so we redirect it to redfish event
552 logging. */
553 std::string buildInfo;
554 std::string action;
555 switch (FWUpdateTarget(target))
556 {
557 case FWUpdateTarget::targetBMC:
558 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700559 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800560 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
561 " BuildID: " + std::to_string(auxInfo);
562 buildInfo += std::to_string(auxInfo);
563 break;
564 case FWUpdateTarget::targetBIOS:
565 firmware = "BIOS";
566 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700567 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800568 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
569 " minor: " +
570 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
571 " ReleaseNumber: " + // ASCII encoded
572 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
573 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
574 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
575 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
576 break;
577 case FWUpdateTarget::targetME:
578 firmware = "ME";
579 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700580 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800581 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
582 " minor2: " +
583 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
584 " build1: " +
585 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
586 " build2: " +
587 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
588 break;
589 case FWUpdateTarget::targetOEMEWS:
590 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700591 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800592 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
593 " BuildID: " + std::to_string(auxInfo);
594 break;
595 }
596
Jason M. Billsdc249272019-04-03 09:58:40 -0700597 static const std::string openBMCMessageRegistryVersion("0.1");
598 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
599
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800600 switch (status)
601 {
602 case 0x0:
603 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700604 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800605 break;
606 case 0x1:
607 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700608 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800609 break;
610 case 0x2:
611 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700612 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800613 break;
614 default:
615 action = "unknown";
616 break;
617 }
618
Jason M. Billsdc249272019-04-03 09:58:40 -0700619 std::string firmwareInstanceStr =
620 firmware + " instance: " + std::to_string(instance);
621 std::string message("[firmware update] " + firmwareInstanceStr +
622 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800623
624 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700625 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
626 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
627 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800628 return ipmi::responseSuccess();
629}
630
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530631ipmi::RspType<uint8_t, std::vector<uint8_t>>
632 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
633 uint2_t slotNumber, uint3_t baseBoardSlotNum,
634 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
635 uint8_t netFn, uint8_t cmd,
636 std::optional<std::vector<uint8_t>> writeData)
637{
638 if (reserved1 || reserved2)
639 {
640 return ipmi::responseInvalidFieldRequest();
641 }
642
643 boost::system::error_code ec;
644 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
645 std::vector<uint8_t>>;
646 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
647 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
648 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
649 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
650 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
651 *writeData);
652 if (ec)
653 {
654 phosphor::logging::log<phosphor::logging::level::ERR>(
655 "Failed to call dbus method SlotIpmbRequest");
656 return ipmi::responseUnspecifiedError();
657 }
658
659 std::vector<uint8_t> dataReceived(0);
660 int status = -1;
661 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
662
663 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
664
665 if (status)
666 {
667 phosphor::logging::log<phosphor::logging::level::ERR>(
668 "Failed to get response from SlotIpmbRequest");
669 return ipmi::responseResponseError();
670 }
671 return ipmi::responseSuccess(cc, dataReceived);
672}
673
Jason M. Bills64796042018-10-03 16:51:55 -0700674ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
675 ipmi_request_t request,
676 ipmi_response_t response,
677 ipmi_data_len_t dataLen,
678 ipmi_context_t context)
679{
680 SetPowerRestoreDelayReq* data =
681 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
682 uint16_t delay = 0;
683
684 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
685 {
686 *dataLen = 0;
687 return IPMI_CC_REQ_DATA_LEN_INVALID;
688 }
689 delay = data->byteMSB;
690 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700691 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700692 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700693 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
694 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700695 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
696 *dataLen = 0;
697
698 return IPMI_CC_OK;
699}
700
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700701static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700702{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700703 static constexpr const char* cpuPresencePathPrefix =
704 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
705 static constexpr const char* cpuPresenceIntf =
706 "xyz.openbmc_project.Inventory.Item";
707 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
708 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
709 try
Jason M. Bills64796042018-10-03 16:51:55 -0700710 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700711 auto service =
712 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
713
714 ipmi::Value result = ipmi::getDbusProperty(
715 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
716 return std::get<bool>(result);
717 }
718 catch (const std::exception& e)
719 {
720 phosphor::logging::log<phosphor::logging::level::INFO>(
721 "Cannot find processor presence",
722 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
723 return false;
724 }
725}
726
727ipmi::RspType<bool, // CATERR Reset Enabled
728 bool, // ERR2 Reset Enabled
729 uint6_t, // reserved
730 uint8_t, // reserved, returns 0x3F
731 uint6_t, // CPU1 CATERR Count
732 uint2_t, // CPU1 Status
733 uint6_t, // CPU2 CATERR Count
734 uint2_t, // CPU2 Status
735 uint6_t, // CPU3 CATERR Count
736 uint2_t, // CPU3 Status
737 uint6_t, // CPU4 CATERR Count
738 uint2_t, // CPU4 Status
739 uint8_t // Crashdump Count
740 >
741 ipmiOEMGetProcessorErrConfig()
742{
743 bool resetOnCATERR = false;
744 bool resetOnERR2 = false;
745 uint6_t cpu1CATERRCount = 0;
746 uint6_t cpu2CATERRCount = 0;
747 uint6_t cpu3CATERRCount = 0;
748 uint6_t cpu4CATERRCount = 0;
749 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700750 uint2_t cpu1Status = cpuPresent("CPU_1")
751 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
752 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
753 uint2_t cpu2Status = cpuPresent("CPU_2")
754 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
755 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
756 uint2_t cpu3Status = cpuPresent("CPU_3")
757 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
758 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
759 uint2_t cpu4Status = cpuPresent("CPU_4")
760 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
761 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700762
763 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
764 try
765 {
766 auto service = ipmi::getService(*busp, processorErrConfigIntf,
767 processorErrConfigObjPath);
768
769 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
770 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
771 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
772 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
773 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
774 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
775 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
776 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
777 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
778 }
779 catch (const std::exception& e)
780 {
781 phosphor::logging::log<phosphor::logging::level::ERR>(
782 "Failed to fetch processor error config",
783 phosphor::logging::entry("ERROR=%s", e.what()));
784 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700785 }
786
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700787 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
788 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
789 cpu2Status, cpu3CATERRCount, cpu3Status,
790 cpu4CATERRCount, cpu4Status, crashdumpCount);
791}
Jason M. Bills64796042018-10-03 16:51:55 -0700792
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700793ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
794 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
795 std::optional<bool> clearCPUErrorCount,
796 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
797{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000798 if (reserved1 || reserved2)
799 {
800 return ipmi::responseInvalidFieldRequest();
801 }
802
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700803 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700804
805 try
806 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000807 if (reserved3.value_or(0))
808 {
809 return ipmi::responseInvalidFieldRequest();
810 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700811 auto service = ipmi::getService(*busp, processorErrConfigIntf,
812 processorErrConfigObjPath);
813 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
814 processorErrConfigIntf, "ResetOnCATERR",
815 resetOnCATERR);
816 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
817 processorErrConfigIntf, "ResetOnERR2",
818 resetOnERR2);
819 if (clearCPUErrorCount.value_or(false))
820 {
821 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700822 processorErrConfigIntf, "ErrorCountCPU1",
823 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700824 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700825 processorErrConfigIntf, "ErrorCountCPU2",
826 static_cast<uint8_t>(0));
827 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
828 processorErrConfigIntf, "ErrorCountCPU3",
829 static_cast<uint8_t>(0));
830 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
831 processorErrConfigIntf, "ErrorCountCPU4",
832 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700833 }
834 if (clearCrashdumpCount.value_or(false))
835 {
836 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700837 processorErrConfigIntf, "CrashdumpCount",
838 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700839 }
Jason M. Bills64796042018-10-03 16:51:55 -0700840 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700841 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700842 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800843 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700844 "Failed to set processor error config",
845 phosphor::logging::entry("EXCEPTION=%s", e.what()));
846 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700847 }
848
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700849 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700850}
851
Yong Li703922d2018-11-06 13:25:31 +0800852ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
853 ipmi_request_t request,
854 ipmi_response_t response,
855 ipmi_data_len_t dataLen,
856 ipmi_context_t context)
857{
858 GetOEMShutdownPolicyRes* resp =
859 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
860
861 if (*dataLen != 0)
862 {
863 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800864 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800865 *dataLen = 0;
866 return IPMI_CC_REQ_DATA_LEN_INVALID;
867 }
868
869 *dataLen = 0;
870
871 try
872 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700873 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800874 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700875 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
876 Value variant = getDbusProperty(
877 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
878 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800879
880 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
881 convertPolicyFromString(std::get<std::string>(variant)) ==
882 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
883 NoShutdownOnOCOT)
884 {
885 resp->policy = 0;
886 }
887 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
888 convertPolicyFromString(std::get<std::string>(variant)) ==
889 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
890 Policy::ShutdownOnOCOT)
891 {
892 resp->policy = 1;
893 }
894 else
895 {
896 phosphor::logging::log<phosphor::logging::level::ERR>(
897 "oem_set_shutdown_policy: invalid property!",
898 phosphor::logging::entry(
899 "PROP=%s", std::get<std::string>(variant).c_str()));
900 return IPMI_CC_UNSPECIFIED_ERROR;
901 }
Yong Li703922d2018-11-06 13:25:31 +0800902 // TODO needs to check if it is multi-node products,
903 // policy is only supported on node 3/4
904 resp->policySupport = shutdownPolicySupported;
905 }
906 catch (sdbusplus::exception_t& e)
907 {
908 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
909 return IPMI_CC_UNSPECIFIED_ERROR;
910 }
911
912 *dataLen = sizeof(GetOEMShutdownPolicyRes);
913 return IPMI_CC_OK;
914}
915
916ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
917 ipmi_request_t request,
918 ipmi_response_t response,
919 ipmi_data_len_t dataLen,
920 ipmi_context_t context)
921{
922 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800923 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
924 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
925 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800926
927 // TODO needs to check if it is multi-node products,
928 // policy is only supported on node 3/4
929 if (*dataLen != 1)
930 {
931 phosphor::logging::log<phosphor::logging::level::ERR>(
932 "oem_set_shutdown_policy: invalid input len!");
933 *dataLen = 0;
934 return IPMI_CC_REQ_DATA_LEN_INVALID;
935 }
936
937 *dataLen = 0;
938 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
939 {
940 phosphor::logging::log<phosphor::logging::level::ERR>(
941 "oem_set_shutdown_policy: invalid input!");
942 return IPMI_CC_INVALID_FIELD_REQUEST;
943 }
944
Yong Li0669d192019-05-06 14:01:46 +0800945 if (*req == noShutdownOnOCOT)
946 {
947 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
948 Policy::NoShutdownOnOCOT;
949 }
950 else
951 {
952 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
953 Policy::ShutdownOnOCOT;
954 }
955
Yong Li703922d2018-11-06 13:25:31 +0800956 try
957 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700958 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800959 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700960 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800961 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700962 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800963 oemShutdownPolicyObjPathProp,
964 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800965 }
966 catch (sdbusplus::exception_t& e)
967 {
968 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
969 return IPMI_CC_UNSPECIFIED_ERROR;
970 }
971
972 return IPMI_CC_OK;
973}
974
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530975/** @brief implementation for check the DHCP or not in IPv4
976 * @param[in] Channel - Channel number
977 * @returns true or false.
978 */
979static bool isDHCPEnabled(uint8_t Channel)
980{
981 try
982 {
983 auto ethdevice = getChannelName(Channel);
984 if (ethdevice.empty())
985 {
986 return false;
987 }
988 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700989 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530990 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700991 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
992 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530993 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700994 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530995 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
996 {
997 return true;
998 }
999 else
1000 {
1001 return false;
1002 }
1003 }
1004 catch (sdbusplus::exception_t& e)
1005 {
1006 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1007 return true;
1008 }
1009}
1010
1011/** @brief implementes for check the DHCP or not in IPv6
1012 * @param[in] Channel - Channel number
1013 * @returns true or false.
1014 */
1015static bool isDHCPIPv6Enabled(uint8_t Channel)
1016{
1017
1018 try
1019 {
1020 auto ethdevice = getChannelName(Channel);
1021 if (ethdevice.empty())
1022 {
1023 return false;
1024 }
1025 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001026 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301027 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001028 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1029 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301030 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001031 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301032 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1033 {
1034 return true;
1035 }
1036 else
1037 {
1038 return false;
1039 }
1040 }
1041 catch (sdbusplus::exception_t& e)
1042 {
1043 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1044 return true;
1045 }
1046}
1047
1048/** @brief implementes the creating of default new user
1049 * @param[in] userName - new username in 16 bytes.
1050 * @param[in] userPassword - new password in 20 bytes
1051 * @returns ipmi completion code.
1052 */
1053ipmi::RspType<> ipmiOEMSetUser2Activation(
1054 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1055 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1056{
1057 bool userState = false;
1058 // Check for System Interface not exist and LAN should be static
1059 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1060 {
Manish Baing440f62b2021-07-15 22:00:37 +00001061 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301062 try
1063 {
1064 getChannelInfo(channel, chInfo);
1065 }
1066 catch (sdbusplus::exception_t& e)
1067 {
1068 phosphor::logging::log<phosphor::logging::level::ERR>(
1069 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1070 phosphor::logging::entry("MSG: %s", e.description()));
1071 return ipmi::response(ipmi::ccUnspecifiedError);
1072 }
1073 if (chInfo.mediumType ==
1074 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1075 {
1076 phosphor::logging::log<phosphor::logging::level::ERR>(
1077 "ipmiOEMSetUser2Activation: system interface exist .");
1078 return ipmi::response(ipmi::ccCommandNotAvailable);
1079 }
1080 else
1081 {
1082
1083 if (chInfo.mediumType ==
1084 static_cast<uint8_t>(EChannelMediumType::lan8032))
1085 {
1086 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1087 {
1088 phosphor::logging::log<phosphor::logging::level::ERR>(
1089 "ipmiOEMSetUser2Activation: DHCP enabled .");
1090 return ipmi::response(ipmi::ccCommandNotAvailable);
1091 }
1092 }
1093 }
1094 }
1095 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1096 if (ipmi::ccSuccess ==
1097 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1098 {
1099 if (enabledUsers > 1)
1100 {
1101 phosphor::logging::log<phosphor::logging::level::ERR>(
1102 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1103 return ipmi::response(ipmi::ccCommandNotAvailable);
1104 }
1105 // Check the user 2 is enabled or not
1106 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1107 if (userState == true)
1108 {
1109 phosphor::logging::log<phosphor::logging::level::ERR>(
1110 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1111 return ipmi::response(ipmi::ccCommandNotAvailable);
1112 }
1113 }
1114 else
1115 {
1116 return ipmi::response(ipmi::ccUnspecifiedError);
1117 }
1118
1119#if BYTE_ORDER == LITTLE_ENDIAN
1120 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1121#endif
1122#if BYTE_ORDER == BIG_ENDIAN
1123 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1124#endif
1125
Vernon Mauery037cabd2020-05-14 12:16:01 -07001126 // ipmiUserSetUserName correctly handles char*, possibly non-null
1127 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001128 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1129 sizeof(userName));
1130 const std::string userNameRaw(
1131 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001132
Vernon Mauery037cabd2020-05-14 12:16:01 -07001133 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301134 {
1135 if (ipmi::ccSuccess ==
1136 ipmiUserSetUserPassword(
1137 ipmiDefaultUserId,
1138 reinterpret_cast<const char*>(userPassword.data())))
1139 {
1140 if (ipmi::ccSuccess ==
1141 ipmiUserSetPrivilegeAccess(
1142 ipmiDefaultUserId,
1143 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1144 privAccess, true))
1145 {
1146 phosphor::logging::log<phosphor::logging::level::INFO>(
1147 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001148 OPENSSL_cleanse(userPassword.data(), userPassword.size());
1149
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301150 return ipmi::responseSuccess();
1151 }
1152 }
1153 // we need to delete the default user id which added in this command as
1154 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001155 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301156 phosphor::logging::log<phosphor::logging::level::ERR>(
1157 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001158 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301159 }
1160 else
1161 {
1162 phosphor::logging::log<phosphor::logging::level::ERR>(
1163 "ipmiOEMSetUser2Activation: Setting username failed.");
1164 }
1165
1166 return ipmi::response(ipmi::ccCommandNotAvailable);
1167}
1168
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301169/** @brief implementes executing the linux command
1170 * @param[in] linux command
1171 * @returns status
1172 */
1173
1174static uint8_t executeCmd(const char* path)
1175{
1176 boost::process::child execProg(path);
1177 execProg.wait();
1178
1179 int retCode = execProg.exit_code();
1180 if (retCode)
1181 {
1182 return ipmi::ccUnspecifiedError;
1183 }
1184 return ipmi::ccSuccess;
1185}
1186
1187/** @brief implementes ASD Security event logging
1188 * @param[in] Event message string
1189 * @param[in] Event Severity
1190 * @returns status
1191 */
1192
1193static void atScaleDebugEventlog(std::string msg, int severity)
1194{
1195 std::string eventStr = "OpenBMC.0.1." + msg;
1196 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1197 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1198 eventStr.c_str(), NULL);
1199}
1200
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301201/** @brief implementes setting password for special user
1202 * @param[in] specialUserIndex
1203 * @param[in] userPassword - new password in 20 bytes
1204 * @returns ipmi completion code.
1205 */
1206ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1207 uint8_t specialUserIndex,
1208 std::vector<uint8_t> userPassword)
1209{
1210 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301211 ipmi_ret_t status = ipmi::ccSuccess;
1212
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301213 try
1214 {
1215 getChannelInfo(ctx->channel, chInfo);
1216 }
1217 catch (sdbusplus::exception_t& e)
1218 {
1219 phosphor::logging::log<phosphor::logging::level::ERR>(
1220 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1221 phosphor::logging::entry("MSG: %s", e.description()));
1222 return ipmi::responseUnspecifiedError();
1223 }
1224 if (chInfo.mediumType !=
1225 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1226 {
1227 phosphor::logging::log<phosphor::logging::level::ERR>(
1228 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1229 "interface");
1230 return ipmi::responseCommandNotAvailable();
1231 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301232
1233 // 0 for root user and 1 for AtScaleDebug is allowed
1234 if (specialUserIndex >
1235 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301236 {
1237 phosphor::logging::log<phosphor::logging::level::ERR>(
1238 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1239 return ipmi::responseParmOutOfRange();
1240 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301241 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301242 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301243 constexpr uint8_t minPasswordSizeRequired = 6;
Patrick Williams23939852021-09-02 11:18:35 -05001244 SecureString passwd;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301245 if (userPassword.size() < minPasswordSizeRequired ||
1246 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1247 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001248 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301249 return ipmi::responseReqDataLenInvalid();
1250 }
1251 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1252 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001253 // Clear sensitive data
1254 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301255 if (specialUserIndex ==
1256 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1257 {
1258 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1259
1260 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1261 }
1262 else
1263 {
1264 status = ipmiSetSpecialUserPassword("root", passwd);
1265 }
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001266 // Clear sensitive data
gokulsankera87dbd42021-07-23 19:23:08 +05301267 OPENSSL_cleanse(passwd.data(), passwd.length());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001268
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301269 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301270 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301271 else
1272 {
1273 if (specialUserIndex ==
1274 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1275 {
1276 status = executeCmd("passwd -d root");
1277 }
1278 else
1279 {
1280
1281 status = executeCmd("passwd -d asdbg");
1282
1283 if (status == 0)
1284 {
1285 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1286 LOG_INFO);
1287 }
1288 }
1289 return ipmi::response(status);
1290 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301291}
1292
Kuiying Wang45f04982018-12-26 09:23:08 +08001293namespace ledAction
1294{
1295using namespace sdbusplus::xyz::openbmc_project::Led::server;
1296std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001297 {Physical::Action::Off, 0},
1298 {Physical::Action::On, 2},
1299 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001300
1301std::map<uint8_t, std::string> offsetObjPath = {
1302 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1303
1304} // namespace ledAction
1305
1306int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1307 const std::string& objPath, uint8_t& state)
1308{
1309 try
1310 {
1311 std::string service = getService(bus, intf, objPath);
1312 Value stateValue =
1313 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001314 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001315 state = ledAction::actionDbusToIpmi.at(
1316 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1317 convertActionFromString(strState));
1318 }
1319 catch (sdbusplus::exception::SdBusError& e)
1320 {
1321 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1322 return -1;
1323 }
1324 return 0;
1325}
1326
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001327ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001328{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001329 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001330 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001331 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001332 for (auto it = ledAction::offsetObjPath.begin();
1333 it != ledAction::offsetObjPath.end(); ++it)
1334 {
1335 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001336 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001337 {
1338 phosphor::logging::log<phosphor::logging::level::ERR>(
1339 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001340 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001341 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001342 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001343 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001344 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001345}
1346
Yong Li23737fe2019-02-19 08:49:55 +08001347ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1348 ipmi_request_t request,
1349 ipmi_response_t response,
1350 ipmi_data_len_t dataLen,
1351 ipmi_context_t context)
1352{
1353 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1354 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1355
1356 if (*dataLen == 0)
1357 {
1358 phosphor::logging::log<phosphor::logging::level::ERR>(
1359 "CfgHostSerial: invalid input len!",
1360 phosphor::logging::entry("LEN=%d", *dataLen));
1361 return IPMI_CC_REQ_DATA_LEN_INVALID;
1362 }
1363
1364 switch (req->command)
1365 {
1366 case getHostSerialCfgCmd:
1367 {
1368 if (*dataLen != 1)
1369 {
1370 phosphor::logging::log<phosphor::logging::level::ERR>(
1371 "CfgHostSerial: invalid input len!");
1372 *dataLen = 0;
1373 return IPMI_CC_REQ_DATA_LEN_INVALID;
1374 }
1375
1376 *dataLen = 0;
1377
1378 boost::process::ipstream is;
1379 std::vector<std::string> data;
1380 std::string line;
1381 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1382 boost::process::std_out > is);
1383
1384 while (c1.running() && std::getline(is, line) && !line.empty())
1385 {
1386 data.push_back(line);
1387 }
1388
1389 c1.wait();
1390 if (c1.exit_code())
1391 {
1392 phosphor::logging::log<phosphor::logging::level::ERR>(
1393 "CfgHostSerial:: error on execute",
1394 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1395 // Using the default value
1396 *resp = 0;
1397 }
1398 else
1399 {
1400 if (data.size() != 1)
1401 {
1402 phosphor::logging::log<phosphor::logging::level::ERR>(
1403 "CfgHostSerial:: error on read env");
1404 return IPMI_CC_UNSPECIFIED_ERROR;
1405 }
1406 try
1407 {
1408 unsigned long tmp = std::stoul(data[0]);
1409 if (tmp > std::numeric_limits<uint8_t>::max())
1410 {
1411 throw std::out_of_range("Out of range");
1412 }
1413 *resp = static_cast<uint8_t>(tmp);
1414 }
1415 catch (const std::invalid_argument& e)
1416 {
1417 phosphor::logging::log<phosphor::logging::level::ERR>(
1418 "invalid config ",
1419 phosphor::logging::entry("ERR=%s", e.what()));
1420 return IPMI_CC_UNSPECIFIED_ERROR;
1421 }
1422 catch (const std::out_of_range& e)
1423 {
1424 phosphor::logging::log<phosphor::logging::level::ERR>(
1425 "out_of_range config ",
1426 phosphor::logging::entry("ERR=%s", e.what()));
1427 return IPMI_CC_UNSPECIFIED_ERROR;
1428 }
1429 }
1430
1431 *dataLen = 1;
1432 break;
1433 }
1434 case setHostSerialCfgCmd:
1435 {
1436 if (*dataLen != sizeof(CfgHostSerialReq))
1437 {
1438 phosphor::logging::log<phosphor::logging::level::ERR>(
1439 "CfgHostSerial: invalid input len!");
1440 *dataLen = 0;
1441 return IPMI_CC_REQ_DATA_LEN_INVALID;
1442 }
1443
1444 *dataLen = 0;
1445
1446 if (req->parameter > HostSerialCfgParamMax)
1447 {
1448 phosphor::logging::log<phosphor::logging::level::ERR>(
1449 "CfgHostSerial: invalid input!");
1450 return IPMI_CC_INVALID_FIELD_REQUEST;
1451 }
1452
1453 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1454 std::to_string(req->parameter));
1455
1456 c1.wait();
1457 if (c1.exit_code())
1458 {
1459 phosphor::logging::log<phosphor::logging::level::ERR>(
1460 "CfgHostSerial:: error on execute",
1461 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1462 return IPMI_CC_UNSPECIFIED_ERROR;
1463 }
1464 break;
1465 }
1466 default:
1467 phosphor::logging::log<phosphor::logging::level::ERR>(
1468 "CfgHostSerial: invalid input!");
1469 *dataLen = 0;
1470 return IPMI_CC_INVALID_FIELD_REQUEST;
1471 }
1472
1473 return IPMI_CC_OK;
1474}
1475
James Feist91244a62019-02-19 15:04:54 -08001476constexpr const char* thermalModeInterface =
1477 "xyz.openbmc_project.Control.ThermalMode";
1478constexpr const char* thermalModePath =
1479 "/xyz/openbmc_project/control/thermal_mode";
1480
1481bool getFanProfileInterface(
1482 sdbusplus::bus::bus& bus,
1483 boost::container::flat_map<
1484 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1485{
1486 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1487 "GetAll");
1488 call.append(thermalModeInterface);
1489 try
1490 {
1491 auto data = bus.call(call);
1492 data.read(resp);
1493 }
1494 catch (sdbusplus::exception_t& e)
1495 {
1496 phosphor::logging::log<phosphor::logging::level::ERR>(
1497 "getFanProfileInterface: can't get thermal mode!",
1498 phosphor::logging::entry("ERR=%s", e.what()));
1499 return false;
1500 }
1501 return true;
1502}
1503
anil kumar appanaf945eee2019-09-25 23:29:11 +00001504/**@brief implements the OEM set fan config.
1505 * @param selectedFanProfile - fan profile to enable
1506 * @param reserved1
1507 * @param performanceMode - Performance/Acoustic mode
1508 * @param reserved2
1509 * @param setPerformanceMode - set Performance/Acoustic mode
1510 * @param setFanProfile - set fan profile
1511 *
1512 * @return IPMI completion code.
1513 **/
1514ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1515
1516 uint2_t reserved1, bool performanceMode,
1517 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301518 bool setFanProfile,
1519 std::optional<uint8_t> dimmGroupId,
1520 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001521{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001522 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001523 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001524 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001525 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301526
1527 if (dimmGroupId)
1528 {
1529 if (*dimmGroupId >= maxCPUNum)
1530 {
1531 return ipmi::responseInvalidFieldRequest();
1532 }
1533 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1534 {
1535 return ipmi::responseInvalidFieldRequest();
1536 }
1537 }
1538
James Feist91244a62019-02-19 15:04:54 -08001539 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001540 boost::container::flat_map<
1541 std::string, std::variant<std::vector<std::string>, std::string>>
1542 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001543 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1544 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001545 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001546 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001547 }
1548
1549 std::vector<std::string>* supported =
1550 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1551 if (supported == nullptr)
1552 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001553 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001554 }
1555 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001556 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001557 {
James Feist91244a62019-02-19 15:04:54 -08001558 if (performanceMode)
1559 {
1560
1561 if (std::find(supported->begin(), supported->end(),
1562 "Performance") != supported->end())
1563 {
1564 mode = "Performance";
1565 }
1566 }
1567 else
1568 {
James Feist91244a62019-02-19 15:04:54 -08001569 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1570 supported->end())
1571 {
1572 mode = "Acoustic";
1573 }
1574 }
1575 if (mode.empty())
1576 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001577 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001578 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001579
1580 try
1581 {
1582 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1583 thermalModeInterface, "Current", mode);
1584 }
1585 catch (sdbusplus::exception_t& e)
1586 {
1587 phosphor::logging::log<phosphor::logging::level::ERR>(
1588 "ipmiOEMSetFanConfig: can't set thermal mode!",
1589 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1590 return ipmi::responseResponseError();
1591 }
James Feist91244a62019-02-19 15:04:54 -08001592 }
1593
anil kumar appanaf945eee2019-09-25 23:29:11 +00001594 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001595}
1596
James Feist5b693632019-07-09 09:06:09 -07001597ipmi::RspType<uint8_t, // profile support map
1598 uint8_t, // fan control profile enable
1599 uint8_t, // flags
1600 uint32_t // dimm presence bit map
1601 >
1602 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001603{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301604 if (dimmGroupId >= maxCPUNum)
1605 {
1606 return ipmi::responseInvalidFieldRequest();
1607 }
1608
1609 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1610
1611 if (!cpuStatus)
1612 {
1613 return ipmi::responseInvalidFieldRequest();
1614 }
1615
James Feist91244a62019-02-19 15:04:54 -08001616 boost::container::flat_map<
1617 std::string, std::variant<std::vector<std::string>, std::string>>
1618 profileData;
1619
Vernon Mauery15419dd2019-05-24 09:40:30 -07001620 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1621 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001622 {
James Feist5b693632019-07-09 09:06:09 -07001623 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001624 }
1625
1626 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1627
1628 if (current == nullptr)
1629 {
1630 phosphor::logging::log<phosphor::logging::level::ERR>(
1631 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001632 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001633 }
1634 bool performance = (*current == "Performance");
1635
James Feist5b693632019-07-09 09:06:09 -07001636 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001637 if (performance)
1638 {
James Feist5b693632019-07-09 09:06:09 -07001639 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001640 }
1641
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001642 constexpr uint8_t fanControlDefaultProfile = 0x80;
1643 constexpr uint8_t fanControlProfileState = 0x00;
1644 constexpr uint32_t dimmPresenceBitmap = 0x00;
1645
1646 return ipmi::responseSuccess(fanControlDefaultProfile,
1647 fanControlProfileState, flags,
1648 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001649}
James Feist5f957ca2019-03-14 15:33:55 -07001650constexpr const char* cfmLimitSettingPath =
1651 "/xyz/openbmc_project/control/cfm_limit";
1652constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001653constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001654constexpr const size_t legacyPCHSensorNumber = 0x22;
1655constexpr const char* exitAirPathName = "Exit_Air";
1656constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001657constexpr const char* pidConfigurationIface =
1658 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001659
James Feist09f6b602019-08-08 11:30:03 -07001660static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001661{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001662 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001663 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001664 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1665 "/xyz/openbmc_project/object_mapper",
1666 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001667
James Feistacc8a4e2019-04-02 14:23:57 -07001668 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001669 std::string path;
1670 GetSubTreeType resp;
1671 try
1672 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001673 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001674 reply.read(resp);
1675 }
1676 catch (sdbusplus::exception_t&)
1677 {
1678 phosphor::logging::log<phosphor::logging::level::ERR>(
1679 "ipmiOEMGetFscParameter: mapper error");
1680 };
James Feist09f6b602019-08-08 11:30:03 -07001681 auto config =
1682 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1683 return pair.first.find(name) != std::string::npos;
1684 });
James Feistfaa4f222019-03-21 16:21:55 -07001685 if (config != resp.end())
1686 {
1687 path = std::move(config->first);
1688 }
1689 return path;
1690}
James Feist5f957ca2019-03-14 15:33:55 -07001691
James Feistacc8a4e2019-04-02 14:23:57 -07001692// flat map to make alphabetical
1693static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1694{
1695 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001696 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001697 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001698 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1699 "/xyz/openbmc_project/object_mapper",
1700 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001701
1702 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1703 GetSubTreeType resp;
1704
1705 try
1706 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001707 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001708 reply.read(resp);
1709 }
1710 catch (sdbusplus::exception_t&)
1711 {
1712 phosphor::logging::log<phosphor::logging::level::ERR>(
1713 "getFanConfigPaths: mapper error");
1714 };
1715 for (const auto& [path, objects] : resp)
1716 {
1717 if (objects.empty())
1718 {
1719 continue; // should be impossible
1720 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001721
1722 try
1723 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001724 ret.emplace(path,
1725 getAllDbusProperties(*dbus, objects[0].first, path,
1726 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001727 }
1728 catch (sdbusplus::exception_t& e)
1729 {
1730 phosphor::logging::log<phosphor::logging::level::ERR>(
1731 "getPidConfigs: can't get DbusProperties!",
1732 phosphor::logging::entry("ERR=%s", e.what()));
1733 }
James Feistacc8a4e2019-04-02 14:23:57 -07001734 }
1735 return ret;
1736}
1737
1738ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1739{
1740 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1741 if (data.empty())
1742 {
1743 return ipmi::responseResponseError();
1744 }
1745 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1746 for (const auto& [_, pid] : data)
1747 {
1748 auto findClass = pid.find("Class");
1749 if (findClass == pid.end())
1750 {
1751 phosphor::logging::log<phosphor::logging::level::ERR>(
1752 "ipmiOEMGetFscParameter: found illegal pid "
1753 "configurations");
1754 return ipmi::responseResponseError();
1755 }
1756 std::string type = std::get<std::string>(findClass->second);
1757 if (type == "fan")
1758 {
1759 auto findOutLimit = pid.find("OutLimitMin");
1760 if (findOutLimit == pid.end())
1761 {
1762 phosphor::logging::log<phosphor::logging::level::ERR>(
1763 "ipmiOEMGetFscParameter: found illegal pid "
1764 "configurations");
1765 return ipmi::responseResponseError();
1766 }
1767 // get the min out of all the offsets
1768 minOffset = std::min(
1769 minOffset,
1770 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1771 }
1772 }
1773 if (minOffset == std::numeric_limits<uint8_t>::max())
1774 {
1775 phosphor::logging::log<phosphor::logging::level::ERR>(
1776 "ipmiOEMGetFscParameter: found no fan configurations!");
1777 return ipmi::responseResponseError();
1778 }
1779
1780 return ipmi::responseSuccess(minOffset);
1781}
1782
1783ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1784{
1785 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1786 if (data.empty())
1787 {
1788
1789 phosphor::logging::log<phosphor::logging::level::ERR>(
1790 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1791 return ipmi::responseResponseError();
1792 }
1793
Vernon Mauery15419dd2019-05-24 09:40:30 -07001794 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001795 bool found = false;
1796 for (const auto& [path, pid] : data)
1797 {
1798 auto findClass = pid.find("Class");
1799 if (findClass == pid.end())
1800 {
1801
1802 phosphor::logging::log<phosphor::logging::level::ERR>(
1803 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1804 "configurations");
1805 return ipmi::responseResponseError();
1806 }
1807 std::string type = std::get<std::string>(findClass->second);
1808 if (type == "fan")
1809 {
1810 auto findOutLimit = pid.find("OutLimitMin");
1811 if (findOutLimit == pid.end())
1812 {
1813
1814 phosphor::logging::log<phosphor::logging::level::ERR>(
1815 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1816 "configurations");
1817 return ipmi::responseResponseError();
1818 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001819 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001820 path, pidConfigurationIface, "OutLimitMin",
1821 static_cast<double>(offset));
1822 found = true;
1823 }
1824 }
1825 if (!found)
1826 {
1827 phosphor::logging::log<phosphor::logging::level::ERR>(
1828 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1829 return ipmi::responseResponseError();
1830 }
1831
1832 return ipmi::responseSuccess();
1833}
1834
1835ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1836 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001837{
1838 constexpr const size_t disableLimiting = 0x0;
1839
Vernon Mauery15419dd2019-05-24 09:40:30 -07001840 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001841 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001842 {
James Feist09f6b602019-08-08 11:30:03 -07001843 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001844 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001845 {
James Feist09f6b602019-08-08 11:30:03 -07001846 pathName = exitAirPathName;
1847 }
1848 else if (param1 == legacyPCHSensorNumber)
1849 {
1850 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001851 }
1852 else
1853 {
James Feistacc8a4e2019-04-02 14:23:57 -07001854 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001855 }
James Feist09f6b602019-08-08 11:30:03 -07001856 std::string path = getConfigPath(pathName);
1857 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1858 pidConfigurationIface, "SetPoint",
1859 static_cast<double>(param2));
1860 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001861 }
James Feistacc8a4e2019-04-02 14:23:57 -07001862 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001863 {
James Feistacc8a4e2019-04-02 14:23:57 -07001864 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001865
1866 // must be greater than 50 based on eps
1867 if (cfm < 50 && cfm != disableLimiting)
1868 {
James Feistacc8a4e2019-04-02 14:23:57 -07001869 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001870 }
1871
1872 try
1873 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001874 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001875 cfmLimitIface, "Limit",
1876 static_cast<double>(cfm));
1877 }
1878 catch (sdbusplus::exception_t& e)
1879 {
1880 phosphor::logging::log<phosphor::logging::level::ERR>(
1881 "ipmiOEMSetFscParameter: can't set cfm setting!",
1882 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001883 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001884 }
James Feistacc8a4e2019-04-02 14:23:57 -07001885 return ipmi::responseSuccess();
1886 }
1887 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1888 {
1889 constexpr const size_t maxDomainCount = 8;
1890 uint8_t requestedDomainMask = param1;
1891 boost::container::flat_map data = getPidConfigs();
1892 if (data.empty())
1893 {
1894
1895 phosphor::logging::log<phosphor::logging::level::ERR>(
1896 "ipmiOEMSetFscParameter: found no pid configurations!");
1897 return ipmi::responseResponseError();
1898 }
1899 size_t count = 0;
1900 for (const auto& [path, pid] : data)
1901 {
1902 auto findClass = pid.find("Class");
1903 if (findClass == pid.end())
1904 {
1905
1906 phosphor::logging::log<phosphor::logging::level::ERR>(
1907 "ipmiOEMSetFscParameter: found illegal pid "
1908 "configurations");
1909 return ipmi::responseResponseError();
1910 }
1911 std::string type = std::get<std::string>(findClass->second);
1912 if (type == "fan")
1913 {
1914 if (requestedDomainMask & (1 << count))
1915 {
1916 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001917 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001918 pidConfigurationIface, "OutLimitMax",
1919 static_cast<double>(param2));
1920 }
1921 count++;
1922 }
1923 }
1924 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001925 }
1926 else
1927 {
1928 // todo other command parts possibly
1929 // tcontrol is handled in peci now
1930 // fan speed offset not implemented yet
1931 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001932 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001933 }
1934}
1935
James Feistacc8a4e2019-04-02 14:23:57 -07001936ipmi::RspType<
1937 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1938 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001939{
James Feist09f6b602019-08-08 11:30:03 -07001940 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001941
Vernon Mauery15419dd2019-05-24 09:40:30 -07001942 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001943 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001944 {
James Feistacc8a4e2019-04-02 14:23:57 -07001945 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001946 {
James Feistacc8a4e2019-04-02 14:23:57 -07001947 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001948 }
1949
James Feist09f6b602019-08-08 11:30:03 -07001950 std::string pathName;
1951
1952 if (*param == legacyExitAirSensorNumber)
1953 {
1954 pathName = exitAirPathName;
1955 }
1956 else if (*param == legacyPCHSensorNumber)
1957 {
1958 pathName = pchPathName;
1959 }
1960 else
James Feistfaa4f222019-03-21 16:21:55 -07001961 {
James Feistacc8a4e2019-04-02 14:23:57 -07001962 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001963 }
James Feist09f6b602019-08-08 11:30:03 -07001964
1965 uint8_t setpoint = legacyDefaultSetpoint;
1966 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001967 if (path.size())
1968 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001969 Value val = ipmi::getDbusProperty(
1970 *dbus, "xyz.openbmc_project.EntityManager", path,
1971 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001972 setpoint = std::floor(std::get<double>(val) + 0.5);
1973 }
1974
1975 // old implementation used to return the "default" and current, we
1976 // don't make the default readily available so just make both the
1977 // same
James Feistfaa4f222019-03-21 16:21:55 -07001978
James Feistacc8a4e2019-04-02 14:23:57 -07001979 return ipmi::responseSuccess(
1980 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001981 }
James Feistacc8a4e2019-04-02 14:23:57 -07001982 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1983 {
1984 constexpr const size_t maxDomainCount = 8;
1985
1986 if (!param)
1987 {
1988 return ipmi::responseReqDataLenInvalid();
1989 }
1990 uint8_t requestedDomain = *param;
1991 if (requestedDomain >= maxDomainCount)
1992 {
1993 return ipmi::responseInvalidFieldRequest();
1994 }
1995
1996 boost::container::flat_map data = getPidConfigs();
1997 if (data.empty())
1998 {
1999 phosphor::logging::log<phosphor::logging::level::ERR>(
2000 "ipmiOEMGetFscParameter: found no pid configurations!");
2001 return ipmi::responseResponseError();
2002 }
2003 size_t count = 0;
2004 for (const auto& [_, pid] : data)
2005 {
2006 auto findClass = pid.find("Class");
2007 if (findClass == pid.end())
2008 {
2009 phosphor::logging::log<phosphor::logging::level::ERR>(
2010 "ipmiOEMGetFscParameter: found illegal pid "
2011 "configurations");
2012 return ipmi::responseResponseError();
2013 }
2014 std::string type = std::get<std::string>(findClass->second);
2015 if (type == "fan")
2016 {
2017 if (requestedDomain == count)
2018 {
2019 auto findOutLimit = pid.find("OutLimitMax");
2020 if (findOutLimit == pid.end())
2021 {
2022 phosphor::logging::log<phosphor::logging::level::ERR>(
2023 "ipmiOEMGetFscParameter: found illegal pid "
2024 "configurations");
2025 return ipmi::responseResponseError();
2026 }
2027
2028 return ipmi::responseSuccess(
2029 static_cast<uint8_t>(std::floor(
2030 std::get<double>(findOutLimit->second) + 0.5)));
2031 }
2032 else
2033 {
2034 count++;
2035 }
2036 }
2037 }
2038
2039 return ipmi::responseInvalidFieldRequest();
2040 }
2041 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002042 {
2043
2044 /*
2045 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002046 previous behavior didn't seem to prevent this, ignore the check for
2047 now.
James Feist5f957ca2019-03-14 15:33:55 -07002048
James Feistacc8a4e2019-04-02 14:23:57 -07002049 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002050 {
2051 phosphor::logging::log<phosphor::logging::level::ERR>(
2052 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002053 return IPMI_CC_REQ_DATA_LEN_INVALID;
2054 }
2055 */
2056 Value cfmLimit;
2057 Value cfmMaximum;
2058 try
2059 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002060 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002061 cfmLimitSettingPath, cfmLimitIface,
2062 "Limit");
2063 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002064 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002065 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2066 }
2067 catch (sdbusplus::exception_t& e)
2068 {
2069 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002070 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002071 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002072 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002073 }
2074
James Feistacc8a4e2019-04-02 14:23:57 -07002075 double cfmMax = std::get<double>(cfmMaximum);
2076 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002077
James Feistacc8a4e2019-04-02 14:23:57 -07002078 cfmLim = std::floor(cfmLim + 0.5);
2079 cfmMax = std::floor(cfmMax + 0.5);
2080 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2081 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002082
James Feistacc8a4e2019-04-02 14:23:57 -07002083 return ipmi::responseSuccess(
2084 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002085 }
James Feistacc8a4e2019-04-02 14:23:57 -07002086
James Feist5f957ca2019-03-14 15:33:55 -07002087 else
2088 {
2089 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002090 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002091 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002092 }
2093}
2094
Cheng C Yang773703a2019-08-15 09:41:11 +08002095using crConfigVariant =
2096 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2097
2098int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2099 const crConfigVariant& value,
2100 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2101{
2102 boost::system::error_code ec;
2103 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002104 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002105 "/xyz/openbmc_project/control/power_supply_redundancy",
2106 "org.freedesktop.DBus.Properties", "Set",
2107 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2108 if (ec)
2109 {
2110 phosphor::logging::log<phosphor::logging::level::ERR>(
2111 "Failed to set dbus property to cold redundancy");
2112 return -1;
2113 }
2114
2115 return 0;
2116}
2117
Kuiying Wange45333a2020-07-22 22:06:37 +08002118int getCRConfig(
2119 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2120 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2121 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002122{
2123 boost::system::error_code ec;
2124 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002125 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002126 "/xyz/openbmc_project/control/power_supply_redundancy",
2127 "org.freedesktop.DBus.Properties", "Get",
2128 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2129 if (ec)
2130 {
2131 phosphor::logging::log<phosphor::logging::level::ERR>(
2132 "Failed to get dbus property to cold redundancy");
2133 return -1;
2134 }
2135 return 0;
2136}
2137
2138uint8_t getPSUCount(void)
2139{
2140 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2141 ipmi::Value num;
2142 try
2143 {
2144 num = ipmi::getDbusProperty(
2145 *dbus, "xyz.openbmc_project.PSURedundancy",
2146 "/xyz/openbmc_project/control/power_supply_redundancy",
2147 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2148 }
2149 catch (sdbusplus::exception_t& e)
2150 {
2151 phosphor::logging::log<phosphor::logging::level::ERR>(
2152 "Failed to get PSUNumber property from dbus interface");
2153 return 0;
2154 }
2155 uint8_t* pNum = std::get_if<uint8_t>(&num);
2156 if (!pNum)
2157 {
2158 phosphor::logging::log<phosphor::logging::level::ERR>(
2159 "Error to get PSU Number");
2160 return 0;
2161 }
2162 return *pNum;
2163}
2164
2165bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2166{
2167 if (conf.size() < num)
2168 {
2169 phosphor::logging::log<phosphor::logging::level::ERR>(
2170 "Invalid PSU Ranking");
2171 return false;
2172 }
2173 std::set<uint8_t> confSet;
2174 for (uint8_t i = 0; i < num; i++)
2175 {
2176 if (conf[i] > num)
2177 {
2178 phosphor::logging::log<phosphor::logging::level::ERR>(
2179 "PSU Ranking is larger than current PSU number");
2180 return false;
2181 }
2182 confSet.emplace(conf[i]);
2183 }
2184
2185 if (confSet.size() != num)
2186 {
2187 phosphor::logging::log<phosphor::logging::level::ERR>(
2188 "duplicate PSU Ranking");
2189 return false;
2190 }
2191 return true;
2192}
2193
2194enum class crParameter
2195{
2196 crStatus = 0,
2197 crFeature = 1,
2198 rotationFeature = 2,
2199 rotationAlgo = 3,
2200 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002201 numOfPSU = 5,
2202 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002203};
2204
2205constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2206static const constexpr uint32_t oneDay = 0x15180;
2207static const constexpr uint32_t oneMonth = 0xf53700;
2208static const constexpr uint8_t userSpecific = 0x01;
2209static const constexpr uint8_t crSetCompleted = 0;
2210ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2211 uint8_t parameter,
2212 ipmi::message::Payload& payload)
2213{
2214 switch (static_cast<crParameter>(parameter))
2215 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002216 case crParameter::rotationFeature:
2217 {
2218 uint8_t param1;
2219 if (payload.unpack(param1) || !payload.fullyUnpacked())
2220 {
2221 return ipmi::responseReqDataLenInvalid();
2222 }
2223 // Rotation Enable can only be true or false
2224 if (param1 > 1)
2225 {
2226 return ipmi::responseInvalidFieldRequest();
2227 }
2228 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2229 {
2230 return ipmi::responseResponseError();
2231 }
2232 break;
2233 }
2234 case crParameter::rotationAlgo:
2235 {
2236 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2237 std::string algoName;
2238 uint8_t param1;
2239 if (payload.unpack(param1))
2240 {
2241 return ipmi::responseReqDataLenInvalid();
2242 }
2243 switch (param1)
2244 {
2245 case 0:
2246 algoName = "xyz.openbmc_project.Control."
2247 "PowerSupplyRedundancy.Algo.bmcSpecific";
2248 break;
2249 case 1:
2250 algoName = "xyz.openbmc_project.Control."
2251 "PowerSupplyRedundancy.Algo.userSpecific";
2252 break;
2253 default:
2254 return ipmi::responseInvalidFieldRequest();
2255 }
2256 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2257 {
2258 return ipmi::responseResponseError();
2259 }
2260
2261 uint8_t numberOfPSU = getPSUCount();
2262 if (!numberOfPSU)
2263 {
2264 return ipmi::responseResponseError();
2265 }
2266 std::vector<uint8_t> rankOrder;
2267
2268 if (param1 == userSpecific)
2269 {
2270 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2271 {
2272 ipmi::responseReqDataLenInvalid();
2273 }
Yong Li83315132019-10-23 17:42:24 +08002274 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002275 {
2276 return ipmi::responseReqDataLenInvalid();
2277 }
2278
2279 if (!validateCRAlgo(rankOrder, numberOfPSU))
2280 {
2281 return ipmi::responseInvalidFieldRequest();
2282 }
2283 }
2284 else
2285 {
2286 if (rankOrder.size() > 0)
2287 {
2288 return ipmi::responseReqDataLenInvalid();
2289 }
2290 for (uint8_t i = 1; i <= numberOfPSU; i++)
2291 {
2292 rankOrder.emplace_back(i);
2293 }
2294 }
2295 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2296 {
2297 return ipmi::responseResponseError();
2298 }
2299 break;
2300 }
2301 case crParameter::rotationPeriod:
2302 {
2303 // Minimum Rotation period is One day (86400 seconds) and Max
2304 // Rotation Period is 6 month (0xf53700 seconds)
2305 uint32_t period;
2306 if (payload.unpack(period) || !payload.fullyUnpacked())
2307 {
2308 return ipmi::responseReqDataLenInvalid();
2309 }
2310 if ((period < oneDay) || (period > oneMonth))
2311 {
2312 return ipmi::responseInvalidFieldRequest();
2313 }
2314 if (setCRConfig(ctx, "PeriodOfRotation", period))
2315 {
2316 return ipmi::responseResponseError();
2317 }
2318 break;
2319 }
2320 default:
2321 {
2322 return ipmi::response(ccParameterNotSupported);
2323 }
2324 }
2325
Cheng C Yang773703a2019-08-15 09:41:11 +08002326 return ipmi::responseSuccess(crSetCompleted);
2327}
2328
Yong Li83315132019-10-23 17:42:24 +08002329ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002330 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2331{
2332 crConfigVariant value;
2333 switch (static_cast<crParameter>(parameter))
2334 {
2335 case crParameter::crStatus:
2336 {
2337 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2338 {
2339 return ipmi::responseResponseError();
2340 }
2341 std::string* pStatus = std::get_if<std::string>(&value);
2342 if (!pStatus)
2343 {
2344 phosphor::logging::log<phosphor::logging::level::ERR>(
2345 "Error to get ColdRedundancyStatus property");
2346 return ipmi::responseResponseError();
2347 }
2348 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2349 auto status =
2350 server::PowerSupplyRedundancy::convertStatusFromString(
2351 *pStatus);
2352 switch (status)
2353 {
2354 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002355 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002356 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002357
2358 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002359 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002360 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002361 default:
2362 phosphor::logging::log<phosphor::logging::level::ERR>(
2363 "Error to get valid status");
2364 return ipmi::responseResponseError();
2365 }
2366 }
2367 case crParameter::crFeature:
2368 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002369 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002370 {
2371 return ipmi::responseResponseError();
2372 }
2373 bool* pResponse = std::get_if<bool>(&value);
2374 if (!pResponse)
2375 {
2376 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002377 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002378 return ipmi::responseResponseError();
2379 }
2380
Cheng C Yangf41e3342019-09-10 04:47:23 +08002381 return ipmi::responseSuccess(parameter,
2382 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002383 }
2384 case crParameter::rotationFeature:
2385 {
2386 if (getCRConfig(ctx, "RotationEnabled", value))
2387 {
2388 return ipmi::responseResponseError();
2389 }
2390 bool* pResponse = std::get_if<bool>(&value);
2391 if (!pResponse)
2392 {
2393 phosphor::logging::log<phosphor::logging::level::ERR>(
2394 "Error to get RotationEnabled property");
2395 return ipmi::responseResponseError();
2396 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002397 return ipmi::responseSuccess(parameter,
2398 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002399 }
2400 case crParameter::rotationAlgo:
2401 {
2402 if (getCRConfig(ctx, "RotationAlgorithm", value))
2403 {
2404 return ipmi::responseResponseError();
2405 }
2406
2407 std::string* pAlgo = std::get_if<std::string>(&value);
2408 if (!pAlgo)
2409 {
2410 phosphor::logging::log<phosphor::logging::level::ERR>(
2411 "Error to get RotationAlgorithm property");
2412 return ipmi::responseResponseError();
2413 }
Yong Li83315132019-10-23 17:42:24 +08002414 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002415 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2416 auto algo =
2417 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002418
Cheng C Yang773703a2019-08-15 09:41:11 +08002419 switch (algo)
2420 {
2421 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002422 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002423 break;
2424 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002425 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002426 break;
2427 default:
2428 phosphor::logging::log<phosphor::logging::level::ERR>(
2429 "Error to get valid algo");
2430 return ipmi::responseResponseError();
2431 }
2432
2433 if (getCRConfig(ctx, "RotationRankOrder", value))
2434 {
2435 return ipmi::responseResponseError();
2436 }
2437 std::vector<uint8_t>* pResponse =
2438 std::get_if<std::vector<uint8_t>>(&value);
2439 if (!pResponse)
2440 {
2441 phosphor::logging::log<phosphor::logging::level::ERR>(
2442 "Error to get RotationRankOrder property");
2443 return ipmi::responseResponseError();
2444 }
Yong Li83315132019-10-23 17:42:24 +08002445
Cheng C Yang773703a2019-08-15 09:41:11 +08002446 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002447 std::back_inserter(response));
2448
Cheng C Yangf41e3342019-09-10 04:47:23 +08002449 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002450 }
2451 case crParameter::rotationPeriod:
2452 {
2453 if (getCRConfig(ctx, "PeriodOfRotation", value))
2454 {
2455 return ipmi::responseResponseError();
2456 }
2457 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2458 if (!pResponse)
2459 {
2460 phosphor::logging::log<phosphor::logging::level::ERR>(
2461 "Error to get RotationAlgorithm property");
2462 return ipmi::responseResponseError();
2463 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002464 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002465 }
2466 case crParameter::numOfPSU:
2467 {
2468 uint8_t numberOfPSU = getPSUCount();
2469 if (!numberOfPSU)
2470 {
2471 return ipmi::responseResponseError();
2472 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002473 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002474 }
Yong Li19445ab2019-12-20 18:25:29 +08002475 case crParameter::rotationRankOrderEffective:
2476 {
2477 if (getCRConfig(ctx, "RotationRankOrder", value,
2478 "xyz.openbmc_project.PSURedundancy"))
2479 {
2480 return ipmi::responseResponseError();
2481 }
2482 std::vector<uint8_t>* pResponse =
2483 std::get_if<std::vector<uint8_t>>(&value);
2484 if (!pResponse)
2485 {
2486 phosphor::logging::log<phosphor::logging::level::ERR>(
2487 "Error to get effective RotationRankOrder property");
2488 return ipmi::responseResponseError();
2489 }
2490 return ipmi::responseSuccess(parameter, *pResponse);
2491 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002492 default:
2493 {
2494 return ipmi::response(ccParameterNotSupported);
2495 }
2496 }
2497}
2498
Zhu, Yungebe560b02019-04-21 21:19:21 -04002499ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2500 uint8_t faultState,
2501 uint8_t faultGroup,
2502 std::array<uint8_t, 8>& ledStateData)
2503{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002504 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2505 static const std::array<std::string, maxFaultType> faultNames = {
2506 "faultFan", "faultTemp", "faultPower",
2507 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002508
2509 constexpr uint8_t maxFaultSource = 0x4;
2510 constexpr uint8_t skipLEDs = 0xFF;
2511 constexpr uint8_t pinSize = 64;
2512 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002513 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002514
Zhikui Rence4e73f2019-12-06 13:59:47 -08002515 // same pin names need to be defined in dts file
2516 static const std::array<std::array<std::string, groupSize>, groupNum>
2517 faultLedPinNames = {{
2518 "LED_CPU1_CH1_DIMM1_FAULT",
2519 "LED_CPU1_CH1_DIMM2_FAULT",
2520 "LED_CPU1_CH2_DIMM1_FAULT",
2521 "LED_CPU1_CH2_DIMM2_FAULT",
2522 "LED_CPU1_CH3_DIMM1_FAULT",
2523 "LED_CPU1_CH3_DIMM2_FAULT",
2524 "LED_CPU1_CH4_DIMM1_FAULT",
2525 "LED_CPU1_CH4_DIMM2_FAULT",
2526 "LED_CPU1_CH5_DIMM1_FAULT",
2527 "LED_CPU1_CH5_DIMM2_FAULT",
2528 "LED_CPU1_CH6_DIMM1_FAULT",
2529 "LED_CPU1_CH6_DIMM2_FAULT",
2530 "",
2531 "",
2532 "",
2533 "", // end of group1
2534 "LED_CPU2_CH1_DIMM1_FAULT",
2535 "LED_CPU2_CH1_DIMM2_FAULT",
2536 "LED_CPU2_CH2_DIMM1_FAULT",
2537 "LED_CPU2_CH2_DIMM2_FAULT",
2538 "LED_CPU2_CH3_DIMM1_FAULT",
2539 "LED_CPU2_CH3_DIMM2_FAULT",
2540 "LED_CPU2_CH4_DIMM1_FAULT",
2541 "LED_CPU2_CH4_DIMM2_FAULT",
2542 "LED_CPU2_CH5_DIMM1_FAULT",
2543 "LED_CPU2_CH5_DIMM2_FAULT",
2544 "LED_CPU2_CH6_DIMM1_FAULT",
2545 "LED_CPU2_CH6_DIMM2_FAULT",
2546 "",
2547 "",
2548 "",
2549 "", // endof group2
2550 "LED_CPU3_CH1_DIMM1_FAULT",
2551 "LED_CPU3_CH1_DIMM2_FAULT",
2552 "LED_CPU3_CH2_DIMM1_FAULT",
2553 "LED_CPU3_CH2_DIMM2_FAULT",
2554 "LED_CPU3_CH3_DIMM1_FAULT",
2555 "LED_CPU3_CH3_DIMM2_FAULT",
2556 "LED_CPU3_CH4_DIMM1_FAULT",
2557 "LED_CPU3_CH4_DIMM2_FAULT",
2558 "LED_CPU3_CH5_DIMM1_FAULT",
2559 "LED_CPU3_CH5_DIMM2_FAULT",
2560 "LED_CPU3_CH6_DIMM1_FAULT",
2561 "LED_CPU3_CH6_DIMM2_FAULT",
2562 "",
2563 "",
2564 "",
2565 "", // end of group3
2566 "LED_CPU4_CH1_DIMM1_FAULT",
2567 "LED_CPU4_CH1_DIMM2_FAULT",
2568 "LED_CPU4_CH2_DIMM1_FAULT",
2569 "LED_CPU4_CH2_DIMM2_FAULT",
2570 "LED_CPU4_CH3_DIMM1_FAULT",
2571 "LED_CPU4_CH3_DIMM2_FAULT",
2572 "LED_CPU4_CH4_DIMM1_FAULT",
2573 "LED_CPU4_CH4_DIMM2_FAULT",
2574 "LED_CPU4_CH5_DIMM1_FAULT",
2575 "LED_CPU4_CH5_DIMM2_FAULT",
2576 "LED_CPU4_CH6_DIMM1_FAULT",
2577 "LED_CPU4_CH6_DIMM2_FAULT",
2578 "",
2579 "",
2580 "",
2581 "", // end of group4
2582 "LED_FAN1_FAULT",
2583 "LED_FAN2_FAULT",
2584 "LED_FAN3_FAULT",
2585 "LED_FAN4_FAULT",
2586 "LED_FAN5_FAULT",
2587 "LED_FAN6_FAULT",
2588 "LED_FAN7_FAULT",
2589 "LED_FAN8_FAULT",
2590 "",
2591 "",
2592 "",
2593 "",
2594 "",
2595 "",
2596 "",
2597 "" // end of group5
2598 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002599
Zhikui Rence4e73f2019-12-06 13:59:47 -08002600 // Validate the source, fault type --
2601 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2602 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2603 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2604 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2605 // definition differs based on fault type (Byte 2)
2606 // Type Fan=> Group: 0=FanGroupID, FF-not used
2607 // Byte 5-11 00h, not used
2608 // Byte12 FanLedState [7:0]-Fans 7:0
2609 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2610 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2611 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2612 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2613 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2614 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2615 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2616 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002617 if ((sourceId >= maxFaultSource) ||
2618 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2619 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2620 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2621 {
2622 return ipmi::responseParmOutOfRange();
2623 }
2624
Zhikui Rence4e73f2019-12-06 13:59:47 -08002625 size_t pinGroupOffset = 0;
2626 size_t pinGroupMax = pinSize / groupSize;
2627 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002628 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002629 pinGroupOffset = 4;
2630 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002631 }
2632
2633 switch (RemoteFaultType(faultType))
2634 {
2635 case (RemoteFaultType::fan):
2636 case (RemoteFaultType::memory):
2637 {
2638 if (faultGroup == skipLEDs)
2639 {
2640 return ipmi::responseSuccess();
2641 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002642 // calculate led state bit filed count, each byte has 8bits
2643 // the maximum bits will be 8 * 8 bits
2644 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002645
2646 // assemble ledState
2647 uint64_t ledState = 0;
2648 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002649 for (int i = 0; i < sizeof(ledStateData); i++)
2650 {
2651 ledState = (uint64_t)(ledState << 8);
2652 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2653 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002654 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002655
Zhikui Rence4e73f2019-12-06 13:59:47 -08002656 for (int group = 0; group < pinGroupMax; group++)
2657 {
2658 for (int i = 0; i < groupSize; i++)
2659 { // skip non-existing pins
2660 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2661 {
2662 continue;
2663 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002664
Zhikui Rence4e73f2019-12-06 13:59:47 -08002665 gpiod::line line = gpiod::find_line(
2666 faultLedPinNames[group + pinGroupOffset][i]);
2667 if (!line)
2668 {
2669 phosphor::logging::log<phosphor::logging::level::ERR>(
2670 "Not Find Led Gpio Device!",
2671 phosphor::logging::entry(
2672 "DEVICE=%s",
2673 faultLedPinNames[group + pinGroupOffset][i]
2674 .c_str()));
2675 hasError = true;
2676 continue;
2677 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002678
Zhikui Rence4e73f2019-12-06 13:59:47 -08002679 bool activeHigh =
2680 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2681 try
2682 {
2683 line.request(
2684 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2685 activeHigh
2686 ? 0
2687 : gpiod::line_request::FLAG_ACTIVE_LOW});
2688 line.set_value(ledStateBits[i + group * groupSize]);
2689 }
2690 catch (std::system_error&)
2691 {
2692 phosphor::logging::log<phosphor::logging::level::ERR>(
2693 "Error write Led Gpio Device!",
2694 phosphor::logging::entry(
2695 "DEVICE=%s",
2696 faultLedPinNames[group + pinGroupOffset][i]
2697 .c_str()));
2698 hasError = true;
2699 continue;
2700 }
2701 } // for int i
2702 }
2703 if (hasError)
2704 {
2705 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002706 }
2707 break;
2708 }
2709 default:
2710 {
2711 // now only support two fault types
2712 return ipmi::responseParmOutOfRange();
2713 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002714 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002715 return ipmi::responseSuccess();
2716}
2717
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302718ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2719{
2720 uint8_t prodId = 0;
2721 try
2722 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002723 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302724 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002725 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302726 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2727 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002728 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302729 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2730 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302731 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2732 }
2733 catch (std::exception& e)
2734 {
2735 phosphor::logging::log<phosphor::logging::level::ERR>(
2736 "ipmiOEMReadBoardProductId: Product ID read failed!",
2737 phosphor::logging::entry("ERR=%s", e.what()));
2738 }
2739 return ipmi::responseSuccess(prodId);
2740}
2741
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302742/** @brief implements the get security mode command
2743 * @param ctx - ctx pointer
2744 *
2745 * @returns IPMI completion code with following data
2746 * - restriction mode value - As specified in
2747 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2748 * - special mode value - As specified in
2749 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2750 */
2751ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2752{
2753 namespace securityNameSpace =
2754 sdbusplus::xyz::openbmc_project::Control::Security::server;
2755 uint8_t restrictionModeValue = 0;
2756 uint8_t specialModeValue = 0;
2757
2758 boost::system::error_code ec;
2759 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002760 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302761 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2762 restricionModeProperty);
2763 if (ec)
2764 {
2765 phosphor::logging::log<phosphor::logging::level::ERR>(
2766 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2767 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2768 return ipmi::responseUnspecifiedError();
2769 }
2770 restrictionModeValue = static_cast<uint8_t>(
2771 securityNameSpace::RestrictionMode::convertModesFromString(
2772 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302773 auto varSpecialMode =
2774 ctx->bus->yield_method_call<std::variant<std::string>>(
2775 ctx->yield, ec, specialModeService, specialModeBasePath,
2776 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2777 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302778 if (ec)
2779 {
2780 phosphor::logging::log<phosphor::logging::level::ERR>(
2781 "ipmiGetSecurityMode: failed to get SpecialMode property",
2782 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2783 // fall through, let us not worry about SpecialMode property, which is
2784 // not required in user scenario
2785 }
2786 else
2787 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302788 specialModeValue = static_cast<uint8_t>(
2789 securityNameSpace::SpecialMode::convertModesFromString(
2790 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302791 }
2792 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2793}
2794
2795/** @brief implements the set security mode command
2796 * Command allows to upgrade the restriction mode and won't allow
2797 * to downgrade from system interface
2798 * @param ctx - ctx pointer
2799 * @param restrictionMode - restriction mode value to be set.
2800 *
2801 * @returns IPMI completion code
2802 */
2803ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302804 uint8_t restrictionMode,
2805 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302806{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302807#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2808 if (specialMode)
2809 {
2810 return ipmi::responseReqDataLenInvalid();
2811 }
2812#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302813 namespace securityNameSpace =
2814 sdbusplus::xyz::openbmc_project::Control::Security::server;
2815
2816 ChannelInfo chInfo;
2817 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2818 {
2819 phosphor::logging::log<phosphor::logging::level::ERR>(
2820 "ipmiSetSecurityMode: Failed to get Channel Info",
2821 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2822 return ipmi::responseUnspecifiedError();
2823 }
2824 auto reqMode =
2825 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2826
2827 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2828 (reqMode >
2829 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2830 {
2831 return ipmi::responseInvalidFieldRequest();
2832 }
2833
2834 boost::system::error_code ec;
2835 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002836 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302837 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2838 restricionModeProperty);
2839 if (ec)
2840 {
2841 phosphor::logging::log<phosphor::logging::level::ERR>(
2842 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2843 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2844 return ipmi::responseUnspecifiedError();
2845 }
2846 auto currentRestrictionMode =
2847 securityNameSpace::RestrictionMode::convertModesFromString(
2848 std::get<std::string>(varRestrMode));
2849
2850 if (chInfo.mediumType !=
2851 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2852 currentRestrictionMode > reqMode)
2853 {
2854 phosphor::logging::log<phosphor::logging::level::ERR>(
2855 "ipmiSetSecurityMode - Downgrading security mode not supported "
2856 "through system interface",
2857 phosphor::logging::entry(
2858 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2859 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2860 return ipmi::responseCommandNotAvailable();
2861 }
2862
2863 ec.clear();
2864 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002865 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302866 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2867 restricionModeProperty,
2868 static_cast<std::variant<std::string>>(
2869 securityNameSpace::convertForMessage(reqMode)));
2870
2871 if (ec)
2872 {
2873 phosphor::logging::log<phosphor::logging::level::ERR>(
2874 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2875 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2876 return ipmi::responseUnspecifiedError();
2877 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302878
2879#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2880 if (specialMode)
2881 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00002882 constexpr uint8_t mfgMode = 0x01;
2883 // Manufacturing mode is reserved. So can't enable this mode.
2884 if (specialMode.value() == mfgMode)
2885 {
2886 phosphor::logging::log<phosphor::logging::level::INFO>(
2887 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
2888 return ipmi::responseInvalidFieldRequest();
2889 }
2890
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302891 ec.clear();
2892 ctx->bus->yield_method_call<>(
2893 ctx->yield, ec, specialModeService, specialModeBasePath,
2894 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2895 specialModeProperty,
2896 static_cast<std::variant<std::string>>(
2897 securityNameSpace::convertForMessage(
2898 static_cast<securityNameSpace::SpecialMode::Modes>(
2899 specialMode.value()))));
2900
2901 if (ec)
2902 {
2903 phosphor::logging::log<phosphor::logging::level::ERR>(
2904 "ipmiSetSecurityMode: failed to set SpecialMode property",
2905 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2906 return ipmi::responseUnspecifiedError();
2907 }
2908 }
2909#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302910 return ipmi::responseSuccess();
2911}
2912
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002913ipmi::RspType<uint8_t /* restore status */>
2914 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2915{
2916 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2917
2918 if (clr != expClr)
2919 {
2920 return ipmi::responseInvalidFieldRequest();
2921 }
2922 constexpr uint8_t cmdStatus = 0;
2923 constexpr uint8_t cmdDefaultRestore = 0xaa;
2924 constexpr uint8_t cmdFullRestore = 0xbb;
2925 constexpr uint8_t cmdFormat = 0xcc;
2926
2927 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2928
2929 switch (cmd)
2930 {
2931 case cmdStatus:
2932 break;
2933 case cmdDefaultRestore:
2934 case cmdFullRestore:
2935 case cmdFormat:
2936 {
2937 // write file to rwfs root
2938 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2939 std::ofstream restoreFile(restoreOpFname);
2940 if (!restoreFile)
2941 {
2942 return ipmi::responseUnspecifiedError();
2943 }
2944 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05302945
2946 phosphor::logging::log<phosphor::logging::level::WARNING>(
2947 "Restore to default will be performed on next BMC boot",
2948 phosphor::logging::entry("ACTION=0x%0X", cmd));
2949
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002950 break;
2951 }
2952 default:
2953 return ipmi::responseInvalidFieldRequest();
2954 }
2955
2956 constexpr uint8_t restorePending = 0;
2957 constexpr uint8_t restoreComplete = 1;
2958
2959 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2960 ? restorePending
2961 : restoreComplete;
2962 return ipmi::responseSuccess(restoreStatus);
2963}
2964
Chen Yugang39736d52019-07-12 16:24:33 +08002965ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2966{
2967 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002968 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002969
2970 try
2971 {
2972 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2973 std::string service =
2974 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2975 Value variant =
2976 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2977 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2978
2979 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2980 std::get<std::string>(variant)))
2981 {
2982 case nmi::NMISource::BMCSourceSignal::None:
2983 bmcSource = static_cast<uint8_t>(NmiSource::none);
2984 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002985 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2986 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002987 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002988 case nmi::NMISource::BMCSourceSignal::Watchdog:
2989 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002990 break;
2991 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2992 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2993 break;
2994 case nmi::NMISource::BMCSourceSignal::MemoryError:
2995 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2996 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002997 case nmi::NMISource::BMCSourceSignal::PciBusError:
2998 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002999 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003000 case nmi::NMISource::BMCSourceSignal::PCH:
3001 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003002 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003003 case nmi::NMISource::BMCSourceSignal::Chipset:
3004 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003005 break;
3006 default:
3007 phosphor::logging::log<phosphor::logging::level::ERR>(
3008 "NMI source: invalid property!",
3009 phosphor::logging::entry(
3010 "PROP=%s", std::get<std::string>(variant).c_str()));
3011 return ipmi::responseResponseError();
3012 }
3013 }
3014 catch (sdbusplus::exception::SdBusError& e)
3015 {
3016 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3017 return ipmi::responseResponseError();
3018 }
3019
3020 return ipmi::responseSuccess(bmcSource);
3021}
3022
3023ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3024{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003025 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003026
3027 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3028 nmi::NMISource::BMCSourceSignal::None;
3029
3030 switch (NmiSource(sourceId))
3031 {
3032 case NmiSource::none:
3033 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3034 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003035 case NmiSource::frontPanelButton:
3036 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003037 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003038 case NmiSource::watchdog:
3039 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003040 break;
3041 case NmiSource::chassisCmd:
3042 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3043 break;
3044 case NmiSource::memoryError:
3045 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3046 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003047 case NmiSource::pciBusError:
3048 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003049 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003050 case NmiSource::pch:
3051 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003052 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003053 case NmiSource::chipset:
3054 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003055 break;
3056 default:
3057 phosphor::logging::log<phosphor::logging::level::ERR>(
3058 "NMI source: invalid property!");
3059 return ipmi::responseResponseError();
3060 }
3061
3062 try
3063 {
3064 // keep NMI signal source
3065 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3066 std::string service =
3067 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003068 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3069 oemNmiBmcSourceObjPathProp,
3070 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003071 // set Enabled property to inform NMI source handling
3072 // to trigger a NMI_OUT BSOD.
3073 // if it's triggered by NMI source property changed,
3074 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3075 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3076 {
3077 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3078 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3079 static_cast<bool>(true));
3080 }
Chen Yugang39736d52019-07-12 16:24:33 +08003081 }
3082 catch (sdbusplus::exception_t& e)
3083 {
3084 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3085 return ipmi::responseResponseError();
3086 }
3087
3088 return ipmi::responseSuccess();
3089}
3090
James Feist63efafa2019-07-24 12:39:21 -07003091namespace dimmOffset
3092{
3093constexpr const char* dimmPower = "DimmPower";
3094constexpr const char* staticCltt = "StaticCltt";
3095constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3096constexpr const char* offsetInterface =
3097 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3098constexpr const char* property = "DimmOffset";
3099
3100}; // namespace dimmOffset
3101
3102ipmi::RspType<>
3103 ipmiOEMSetDimmOffset(uint8_t type,
3104 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3105{
3106 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3107 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3108 {
3109 return ipmi::responseInvalidFieldRequest();
3110 }
3111
3112 if (data.empty())
3113 {
3114 return ipmi::responseInvalidFieldRequest();
3115 }
3116 nlohmann::json json;
3117
3118 std::ifstream jsonStream(dimmOffsetFile);
3119 if (jsonStream.good())
3120 {
3121 json = nlohmann::json::parse(jsonStream, nullptr, false);
3122 if (json.is_discarded())
3123 {
3124 json = nlohmann::json();
3125 }
3126 jsonStream.close();
3127 }
3128
3129 std::string typeName;
3130 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3131 {
3132 typeName = dimmOffset::dimmPower;
3133 }
3134 else
3135 {
3136 typeName = dimmOffset::staticCltt;
3137 }
3138
3139 nlohmann::json& field = json[typeName];
3140
3141 for (const auto& [index, value] : data)
3142 {
3143 field[index] = value;
3144 }
3145
3146 for (nlohmann::json& val : field)
3147 {
3148 if (val == nullptr)
3149 {
3150 val = static_cast<uint8_t>(0);
3151 }
3152 }
3153
3154 std::ofstream output(dimmOffsetFile);
3155 if (!output.good())
3156 {
3157 std::cerr << "Error writing json file\n";
3158 return ipmi::responseResponseError();
3159 }
3160
3161 output << json.dump(4);
3162
3163 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3164 {
3165 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3166
3167 std::variant<std::vector<uint8_t>> offsets =
3168 field.get<std::vector<uint8_t>>();
3169 auto call = bus->new_method_call(
3170 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3171 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3172 try
3173 {
3174 bus->call(call);
3175 }
3176 catch (sdbusplus::exception_t& e)
3177 {
3178 phosphor::logging::log<phosphor::logging::level::ERR>(
3179 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3180 phosphor::logging::entry("ERR=%s", e.what()));
3181 return ipmi::responseResponseError();
3182 }
3183 }
3184
3185 return ipmi::responseSuccess();
3186}
3187
3188ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3189{
3190
3191 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3192 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3193 {
3194 return ipmi::responseInvalidFieldRequest();
3195 }
3196
3197 std::ifstream jsonStream(dimmOffsetFile);
3198
3199 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3200 if (json.is_discarded())
3201 {
3202 std::cerr << "File error in " << dimmOffsetFile << "\n";
3203 return ipmi::responseResponseError();
3204 }
3205
3206 std::string typeName;
3207 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3208 {
3209 typeName = dimmOffset::dimmPower;
3210 }
3211 else
3212 {
3213 typeName = dimmOffset::staticCltt;
3214 }
3215
3216 auto it = json.find(typeName);
3217 if (it == json.end())
3218 {
3219 return ipmi::responseInvalidFieldRequest();
3220 }
3221
3222 if (it->size() <= index)
3223 {
3224 return ipmi::responseInvalidFieldRequest();
3225 }
3226
3227 uint8_t resp = it->at(index).get<uint8_t>();
3228 return ipmi::responseSuccess(resp);
3229}
3230
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003231namespace boot_options
3232{
3233
3234using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3235using IpmiValue = uint8_t;
3236constexpr auto ipmiDefault = 0;
3237
3238std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3239 {0x01, Source::Sources::Network},
3240 {0x02, Source::Sources::Disk},
3241 {0x05, Source::Sources::ExternalMedia},
3242 {0x0f, Source::Sources::RemovableMedia},
3243 {ipmiDefault, Source::Sources::Default}};
3244
3245std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003246 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003247
3248std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3249 {Source::Sources::Network, 0x01},
3250 {Source::Sources::Disk, 0x02},
3251 {Source::Sources::ExternalMedia, 0x05},
3252 {Source::Sources::RemovableMedia, 0x0f},
3253 {Source::Sources::Default, ipmiDefault}};
3254
3255std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003256 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003257
3258static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3259static constexpr auto bootSourceIntf =
3260 "xyz.openbmc_project.Control.Boot.Source";
3261static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3262static constexpr auto persistentObjPath =
3263 "/xyz/openbmc_project/control/host0/boot";
3264static constexpr auto oneTimePath =
3265 "/xyz/openbmc_project/control/host0/boot/one_time";
3266static constexpr auto bootSourceProp = "BootSource";
3267static constexpr auto bootModeProp = "BootMode";
3268static constexpr auto oneTimeBootEnableProp = "Enabled";
3269static constexpr auto httpBootMode =
3270 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3271
3272enum class BootOptionParameter : size_t
3273{
3274 setInProgress = 0x0,
3275 bootFlags = 0x5,
3276};
3277static constexpr uint8_t setComplete = 0x0;
3278static constexpr uint8_t setInProgress = 0x1;
3279static uint8_t transferStatus = setComplete;
3280static constexpr uint8_t setParmVersion = 0x01;
3281static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3282static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3283static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3284static constexpr uint8_t httpBoot = 0xd;
3285static constexpr uint8_t bootSourceMask = 0x3c;
3286
3287} // namespace boot_options
3288
3289ipmi::RspType<uint8_t, // version
3290 uint8_t, // param
3291 uint8_t, // data0, dependent on parameter
3292 std::optional<uint8_t> // data1, dependent on parameter
3293 >
3294 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3295{
3296 using namespace boot_options;
3297 uint8_t bootOption = 0;
3298
3299 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3300 {
3301 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3302 std::nullopt);
3303 }
3304
3305 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3306 {
3307 phosphor::logging::log<phosphor::logging::level::ERR>(
3308 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003309 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003310 }
3311
3312 try
3313 {
3314 auto oneTimeEnabled = false;
3315 // read one time Enabled property
3316 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3317 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3318 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3319 enabledIntf, oneTimeBootEnableProp);
3320 oneTimeEnabled = std::get<bool>(variant);
3321
3322 // get BootSource and BootMode properties
3323 // according to oneTimeEnable
3324 auto bootObjPath = oneTimePath;
3325 if (oneTimeEnabled == false)
3326 {
3327 bootObjPath = persistentObjPath;
3328 }
3329
3330 service = getService(*dbus, bootModeIntf, bootObjPath);
3331 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3332 bootModeProp);
3333
3334 auto bootMode =
3335 Mode::convertModesFromString(std::get<std::string>(variant));
3336
3337 service = getService(*dbus, bootSourceIntf, bootObjPath);
3338 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3339 bootSourceProp);
3340
3341 if (std::get<std::string>(variant) == httpBootMode)
3342 {
3343 bootOption = httpBoot;
3344 }
3345 else
3346 {
3347 auto bootSource = Source::convertSourcesFromString(
3348 std::get<std::string>(variant));
3349 bootOption = sourceDbusToIpmi.at(bootSource);
3350 if (Source::Sources::Default == bootSource)
3351 {
3352 bootOption = modeDbusToIpmi.at(bootMode);
3353 }
3354 }
3355
3356 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3357 : setParmBootFlagsValidPermanent;
3358 bootOption <<= 2; // shift for responseconstexpr
3359 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3360 bootOption);
3361 }
3362 catch (sdbusplus::exception_t& e)
3363 {
3364 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3365 return ipmi::responseResponseError();
3366 }
3367}
3368
3369ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3370 std::optional<uint8_t> bootOption)
3371{
3372 using namespace boot_options;
3373 auto oneTimeEnabled = false;
3374
3375 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3376 {
3377 if (bootOption)
3378 {
3379 return ipmi::responseReqDataLenInvalid();
3380 }
3381
3382 if (transferStatus == setInProgress)
3383 {
3384 phosphor::logging::log<phosphor::logging::level::ERR>(
3385 "boot option set in progress!");
3386 return ipmi::responseResponseError();
3387 }
3388
3389 transferStatus = bootParam;
3390 return ipmi::responseSuccess();
3391 }
3392
3393 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3394 {
3395 phosphor::logging::log<phosphor::logging::level::ERR>(
3396 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003397 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003398 }
3399
3400 if (!bootOption)
3401 {
3402 return ipmi::responseReqDataLenInvalid();
3403 }
3404
3405 if (((bootOption.value() & bootSourceMask) >> 2) !=
3406 httpBoot) // not http boot, exit
3407 {
3408 phosphor::logging::log<phosphor::logging::level::ERR>(
3409 "wrong boot option parameter!");
3410 return ipmi::responseParmOutOfRange();
3411 }
3412
3413 try
3414 {
3415 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3416 setParmBootFlagsPermanent;
3417
3418 // read one time Enabled property
3419 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3420 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3421 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3422 enabledIntf, oneTimeBootEnableProp);
3423 oneTimeEnabled = std::get<bool>(variant);
3424
3425 /*
3426 * Check if the current boot setting is onetime or permanent, if the
3427 * request in the command is otherwise, then set the "Enabled"
3428 * property in one_time object path to 'True' to indicate onetime
3429 * and 'False' to indicate permanent.
3430 *
3431 * Once the onetime/permanent setting is applied, then the bootMode
3432 * and bootSource is updated for the corresponding object.
3433 */
3434 if (permanent == oneTimeEnabled)
3435 {
3436 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3437 oneTimeBootEnableProp, !permanent);
3438 }
3439
3440 // set BootSource and BootMode properties
3441 // according to oneTimeEnable or persistent
3442 auto bootObjPath = oneTimePath;
3443 if (oneTimeEnabled == false)
3444 {
3445 bootObjPath = persistentObjPath;
3446 }
3447 std::string bootMode =
3448 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3449 std::string bootSource = httpBootMode;
3450
3451 service = getService(*dbus, bootModeIntf, bootObjPath);
3452 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3453 bootMode);
3454
3455 service = getService(*dbus, bootSourceIntf, bootObjPath);
3456 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3457 bootSourceProp, bootSource);
3458 }
3459 catch (sdbusplus::exception_t& e)
3460 {
3461 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3462 return ipmi::responseResponseError();
3463 }
3464
3465 return ipmi::responseSuccess();
3466}
3467
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003468using BasicVariantType =
3469 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3470 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3471 uint16_t, uint8_t, bool>;
3472using PropertyMapType =
3473 boost::container::flat_map<std::string, BasicVariantType>;
3474static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3475 "xyz.openbmc_project.Configuration.PSUPresence"};
3476int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3477 std::vector<uint64_t>& addrTable)
3478{
3479 boost::system::error_code ec;
3480 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3481 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3482 "/xyz/openbmc_project/object_mapper",
3483 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3484 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3485 if (ec)
3486 {
3487 phosphor::logging::log<phosphor::logging::level::ERR>(
3488 "Failed to set dbus property to cold redundancy");
3489 return -1;
3490 }
3491 for (const auto& object : subtree)
3492 {
3493 std::string pathName = object.first;
3494 for (const auto& serviceIface : object.second)
3495 {
3496 std::string serviceName = serviceIface.first;
3497
3498 ec.clear();
3499 PropertyMapType propMap =
3500 ctx->bus->yield_method_call<PropertyMapType>(
3501 ctx->yield, ec, serviceName, pathName,
3502 "org.freedesktop.DBus.Properties", "GetAll",
3503 "xyz.openbmc_project.Configuration.PSUPresence");
3504 if (ec)
3505 {
3506 phosphor::logging::log<phosphor::logging::level::ERR>(
3507 "Failed to set dbus property to cold redundancy");
3508 return -1;
3509 }
3510 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3511 auto psuAddress =
3512 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3513
3514 if (psuBus == nullptr || psuAddress == nullptr)
3515 {
3516 std::cerr << "error finding necessary "
3517 "entry in configuration\n";
3518 return -1;
3519 }
3520 bus = static_cast<uint8_t>(*psuBus);
3521 addrTable = *psuAddress;
3522 return 0;
3523 }
3524 }
3525 return -1;
3526}
3527
3528static const constexpr uint8_t addrOffset = 8;
3529static const constexpr uint8_t psuRevision = 0xd9;
3530static const constexpr uint8_t defaultPSUBus = 7;
3531// Second Minor, Primary Minor, Major
3532static const constexpr size_t verLen = 3;
3533ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3534{
3535 uint8_t bus = defaultPSUBus;
3536 std::vector<uint64_t> addrTable;
3537 std::vector<uint8_t> result;
3538 if (getPSUAddress(ctx, bus, addrTable))
3539 {
3540 std::cerr << "Failed to get PSU bus and address\n";
3541 return ipmi::responseResponseError();
3542 }
3543
3544 for (const auto& slaveAddr : addrTable)
3545 {
3546 std::vector<uint8_t> writeData = {psuRevision};
3547 std::vector<uint8_t> readBuf(verLen);
3548 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3549 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3550
3551 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3552 if (retI2C != ipmi::ccSuccess)
3553 {
3554 for (size_t idx = 0; idx < verLen; idx++)
3555 {
3556 result.emplace_back(0x00);
3557 }
3558 }
3559 else
3560 {
3561 for (const uint8_t& data : readBuf)
3562 {
3563 result.emplace_back(data);
3564 }
3565 }
3566 }
3567
3568 return ipmi::responseSuccess(result);
3569}
3570
srikanta mondal2030d7c2020-05-03 17:25:25 +00003571std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3572 const std::string& name)
3573{
3574 Value dbusValue = 0;
3575 std::string serviceName;
3576
3577 boost::system::error_code ec =
3578 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3579
3580 if (ec)
3581 {
3582 phosphor::logging::log<phosphor::logging::level::ERR>(
3583 "Failed to perform Multinode getService.");
3584 return std::nullopt;
3585 }
3586
3587 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3588 multiNodeIntf, name, dbusValue);
3589 if (ec)
3590 {
3591 phosphor::logging::log<phosphor::logging::level::ERR>(
3592 "Failed to perform Multinode get property");
3593 return std::nullopt;
3594 }
3595
3596 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3597 if (!multiNodeVal)
3598 {
3599 phosphor::logging::log<phosphor::logging::level::ERR>(
3600 "getMultiNodeInfoPresence: error to get multinode");
3601 return std::nullopt;
3602 }
3603 return *multiNodeVal;
3604}
3605
3606/** @brief implements OEM get reading command
3607 * @param domain ID
3608 * @param reading Type
3609 * - 00h = platform Power Consumption
3610 * - 01h = inlet Air Temp
3611 * - 02h = icc_TDC from PECI
3612 * @param reserved, write as 0000h
3613 *
3614 * @returns IPMI completion code plus response data
3615 * - response
3616 * - domain ID
3617 * - reading Type
3618 * - 00h = platform Power Consumption
3619 * - 01h = inlet Air Temp
3620 * - 02h = icc_TDC from PECI
3621 * - reading
3622 */
3623ipmi::RspType<uint4_t, // domain ID
3624 uint4_t, // reading Type
3625 uint16_t // reading Value
3626 >
3627 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3628 uint4_t readingType, uint16_t reserved)
3629{
3630 constexpr uint8_t platformPower = 0;
3631 constexpr uint8_t inletAirTemp = 1;
3632 constexpr uint8_t iccTdc = 2;
3633
3634 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3635 {
3636 return ipmi::responseInvalidFieldRequest();
3637 }
3638
3639 // This command should run only from multi-node product.
3640 // For all other platforms this command will return invalid.
3641
3642 std::optional<uint8_t> nodeInfo =
3643 getMultiNodeInfoPresence(ctx, "NodePresence");
3644 if (!nodeInfo || !*nodeInfo)
3645 {
3646 return ipmi::responseInvalidCommand();
3647 }
3648
3649 uint16_t oemReadingValue = 0;
3650 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3651 {
3652 double value = 0;
3653 boost::system::error_code ec = ipmi::getDbusProperty(
3654 ctx, "xyz.openbmc_project.HwmonTempSensor",
3655 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3656 "xyz.openbmc_project.Sensor.Value", "Value", value);
3657 if (ec)
3658 {
3659 phosphor::logging::log<phosphor::logging::level::ERR>(
3660 "Failed to get BMC Get OEM temperature",
3661 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3662 return ipmi::responseUnspecifiedError();
3663 }
3664 // Take the Inlet temperature
3665 oemReadingValue = static_cast<uint16_t>(value);
3666 }
3667 else
3668 {
3669 phosphor::logging::log<phosphor::logging::level::ERR>(
3670 "Currently Get OEM Reading support only for Inlet Air Temp");
3671 return ipmi::responseParmOutOfRange();
3672 }
3673 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3674}
3675
AppaRao Puli28972062019-11-11 02:04:45 +05303676/** @brief implements the maximum size of
3677 * bridgeable messages used between KCS and
3678 * IPMB interfacesget security mode command.
3679 *
3680 * @returns IPMI completion code with following data
3681 * - KCS Buffer Size (In multiples of four bytes)
3682 * - IPMB Buffer Size (In multiples of four bytes)
3683 **/
3684ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3685{
3686 // for now this is hard coded; really this number is dependent on
3687 // the BMC kcs driver as well as the host kcs driver....
3688 // we can't know the latter.
3689 uint8_t kcsMaxBufferSize = 63 / 4;
3690 uint8_t ipmbMaxBufferSize = 128 / 4;
3691
3692 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3693}
3694
Jason M. Bills64796042018-10-03 16:51:55 -07003695static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003696{
3697 phosphor::logging::log<phosphor::logging::level::INFO>(
3698 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003699 ipmiPrintAndRegister(intel::netFnGeneral,
3700 intel::general::cmdGetChassisIdentifier, NULL,
3701 ipmiOEMGetChassisIdentifier,
3702 PRIVILEGE_USER); // get chassis identifier
3703
3704 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3705 NULL, ipmiOEMSetSystemGUID,
3706 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003707
3708 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003709 registerHandler(prioOemBase, intel::netFnGeneral,
3710 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3711 ipmiOEMDisableBMCSystemReset);
3712
Jason M. Billsb02bf092019-08-15 13:01:56 -07003713 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003714 registerHandler(prioOemBase, intel::netFnGeneral,
3715 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3716 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003717
Vernon Mauery98bbf692019-09-16 11:14:59 -07003718 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3719 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003720
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003721 registerHandler(prioOemBase, intel::netFnGeneral,
3722 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3723 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003724
Vernon Mauery98bbf692019-09-16 11:14:59 -07003725 ipmiPrintAndRegister(intel::netFnGeneral,
3726 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3727 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303728
Vernon Mauery98bbf692019-09-16 11:14:59 -07003729 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3730 intel::general::cmdSendEmbeddedFWUpdStatus,
3731 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303732
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303733 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3734 Privilege::Admin, ipmiOEMSlotIpmb);
3735
Vernon Mauery98bbf692019-09-16 11:14:59 -07003736 ipmiPrintAndRegister(intel::netFnGeneral,
3737 intel::general::cmdSetPowerRestoreDelay, NULL,
3738 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3739
3740 ipmiPrintAndRegister(intel::netFnGeneral,
3741 intel::general::cmdGetPowerRestoreDelay, NULL,
3742 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3743
3744 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3745 intel::general::cmdSetOEMUser2Activation,
3746 Privilege::Callback, ipmiOEMSetUser2Activation);
3747
3748 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3749 intel::general::cmdSetSpecialUserPassword,
3750 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303751
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003752 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003753 registerHandler(prioOemBase, intel::netFnGeneral,
3754 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3755 ipmiOEMGetProcessorErrConfig);
3756
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003757 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003758 registerHandler(prioOemBase, intel::netFnGeneral,
3759 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3760 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003761
Vernon Mauery98bbf692019-09-16 11:14:59 -07003762 ipmiPrintAndRegister(intel::netFnGeneral,
3763 intel::general::cmdSetShutdownPolicy, NULL,
3764 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003765
Vernon Mauery98bbf692019-09-16 11:14:59 -07003766 ipmiPrintAndRegister(intel::netFnGeneral,
3767 intel::general::cmdGetShutdownPolicy, NULL,
3768 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003769
anil kumar appanaf945eee2019-09-25 23:29:11 +00003770 registerHandler(prioOemBase, intel::netFnGeneral,
3771 intel::general::cmdSetFanConfig, Privilege::User,
3772 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003773
Vernon Mauery98bbf692019-09-16 11:14:59 -07003774 registerHandler(prioOemBase, intel::netFnGeneral,
3775 intel::general::cmdGetFanConfig, Privilege::User,
3776 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003777
Vernon Mauery98bbf692019-09-16 11:14:59 -07003778 registerHandler(prioOemBase, intel::netFnGeneral,
3779 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3780 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003781
Vernon Mauery98bbf692019-09-16 11:14:59 -07003782 registerHandler(prioOemBase, intel::netFnGeneral,
3783 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3784 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003785
Vernon Mauery98bbf692019-09-16 11:14:59 -07003786 registerHandler(prioOemBase, intel::netFnGeneral,
3787 intel::general::cmdSetFscParameter, Privilege::User,
3788 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003789
Vernon Mauery98bbf692019-09-16 11:14:59 -07003790 registerHandler(prioOemBase, intel::netFnGeneral,
3791 intel::general::cmdGetFscParameter, Privilege::User,
3792 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303793
Vernon Mauery98bbf692019-09-16 11:14:59 -07003794 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3795 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3796 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003797
Vernon Mauery98bbf692019-09-16 11:14:59 -07003798 registerHandler(prioOemBase, intel::netFnGeneral,
3799 intel::general::cmdGetNmiStatus, Privilege::User,
3800 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003801
Vernon Mauery98bbf692019-09-16 11:14:59 -07003802 registerHandler(prioOemBase, intel::netFnGeneral,
3803 intel::general::cmdSetNmiStatus, Privilege::Operator,
3804 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003805
Vernon Mauery98bbf692019-09-16 11:14:59 -07003806 registerHandler(prioOemBase, intel::netFnGeneral,
3807 intel::general::cmdGetEfiBootOptions, Privilege::User,
3808 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003809
Vernon Mauery98bbf692019-09-16 11:14:59 -07003810 registerHandler(prioOemBase, intel::netFnGeneral,
3811 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3812 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303813
Vernon Mauery98bbf692019-09-16 11:14:59 -07003814 registerHandler(prioOemBase, intel::netFnGeneral,
3815 intel::general::cmdGetSecurityMode, Privilege::User,
3816 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303817
Vernon Mauery98bbf692019-09-16 11:14:59 -07003818 registerHandler(prioOemBase, intel::netFnGeneral,
3819 intel::general::cmdSetSecurityMode, Privilege::Admin,
3820 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003821
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003822 registerHandler(prioOemBase, intel::netFnGeneral,
3823 intel::general::cmdGetLEDStatus, Privilege::Admin,
3824 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003825
Vernon Mauery98bbf692019-09-16 11:14:59 -07003826 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3827 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3828 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3829
3830 registerHandler(prioOemBase, intel::netFnGeneral,
3831 intel::general::cmdSetFaultIndication, Privilege::Operator,
3832 ipmiOEMSetFaultIndication);
3833
3834 registerHandler(prioOemBase, intel::netFnGeneral,
3835 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3836 ipmiOEMSetCRConfig);
3837
3838 registerHandler(prioOemBase, intel::netFnGeneral,
3839 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3840 ipmiOEMGetCRConfig);
3841
3842 registerHandler(prioOemBase, intel::netFnGeneral,
3843 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003844 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003845
Vernon Mauery98bbf692019-09-16 11:14:59 -07003846 registerHandler(prioOemBase, intel::netFnGeneral,
3847 intel::general::cmdSetDimmOffset, Privilege::Operator,
3848 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003849
Vernon Mauery98bbf692019-09-16 11:14:59 -07003850 registerHandler(prioOemBase, intel::netFnGeneral,
3851 intel::general::cmdGetDimmOffset, Privilege::Operator,
3852 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003853
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003854 registerHandler(prioOemBase, intel::netFnGeneral,
3855 intel::general::cmdGetPSUVersion, Privilege::User,
3856 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303857
3858 registerHandler(prioOemBase, intel::netFnGeneral,
3859 intel::general::cmdGetBufferSize, Privilege::User,
3860 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00003861
3862 registerHandler(prioOemBase, intel::netFnGeneral,
3863 intel::general::cmdOEMGetReading, Privilege::User,
3864 ipmiOEMGetReading);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003865}
3866
3867} // namespace ipmi