blob: 5d42e594f7f118e93850f97da3d60dd8320390d1 [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]));
353 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
354 }
355 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800356 return true;
357}
358
359ipmi::RspType<
360 std::variant<std::string,
361 std::tuple<uint8_t, std::array<uint8_t, 2>,
362 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
363 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
364 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530365 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
366 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530367 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800368{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800369 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
370 {
371 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800372 }
373
374 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800375 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800376 {
377 case OEMDevEntityType::biosId:
378 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530379 // Byte 2&3, Only used with selecting BIOS
380 if (!countToRead || !offset)
381 {
382 return ipmi::responseReqDataLenInvalid();
383 }
384
Vernon Mauery15419dd2019-05-24 09:40:30 -0700385 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800386 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000387 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800388 try
389 {
Yong Li2742b852019-12-16 14:55:11 +0800390 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000391 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800392 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700393 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530394 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800395 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800396 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800397 }
Jason M. Bills64796042018-10-03 16:51:55 -0700398 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530399 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700400 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530401 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700402 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800403 else
404 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530405 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800406 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800407
408 std::string readBuf = {0};
409 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530410 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800411 (readBuf.begin()));
412 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800413 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700414 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800415 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800416 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800417 }
418 }
419 break;
420
421 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800422 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530423 // Byte 2&3, Only used with selecting BIOS
424 if (countToRead || offset)
425 {
426 return ipmi::responseReqDataLenInvalid();
427 }
428
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800429 constexpr const size_t verLen = 2;
430 constexpr const size_t verTotalLen = 10;
431 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
432 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
433 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
434 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
435 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
436 // data0/1: BMC version number; data6/7: ME version number
437 // the others: HSC0/1/2 version number, not avaible.
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530438 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800439 {
440 return ipmi::responseUnspecifiedError();
441 }
442 return ipmi::responseSuccess(
443 std::tuple<
444 uint8_t, std::array<uint8_t, verLen>,
445 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
446 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
447 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
448 }
449 break;
450
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800451 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800452 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530453 // Byte 2&3, Only used with selecting BIOS
454 if (countToRead || offset)
455 {
456 return ipmi::responseReqDataLenInvalid();
457 }
458
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800459 constexpr const size_t sdrLen = 2;
460 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
461 return ipmi::responseSuccess(
462 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
463 readBuf});
464 }
465 break;
466
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800467 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800468 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800469 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800470}
471
472ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
473 ipmi_request_t request, ipmi_response_t response,
474 ipmi_data_len_t dataLen, ipmi_context_t context)
475{
476 if (*dataLen != 0)
477 {
Jason M. Bills64796042018-10-03 16:51:55 -0700478 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800479 return IPMI_CC_REQ_DATA_LEN_INVALID;
480 }
481
482 *dataLen = 1;
483 uint8_t* res = reinterpret_cast<uint8_t*>(response);
484 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
485 // AIC is available so that BIOS will not timeout repeatly which leads to
486 // slow booting.
487 *res = 0; // Byte1=Count of SlotPosition/FruID records.
488 return IPMI_CC_OK;
489}
490
Jason M. Bills64796042018-10-03 16:51:55 -0700491ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
492 ipmi_request_t request,
493 ipmi_response_t response,
494 ipmi_data_len_t dataLen,
495 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800496{
Jason M. Bills64796042018-10-03 16:51:55 -0700497 GetPowerRestoreDelayRes* resp =
498 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
499
500 if (*dataLen != 0)
501 {
502 *dataLen = 0;
503 return IPMI_CC_REQ_DATA_LEN_INVALID;
504 }
505
Vernon Mauery15419dd2019-05-24 09:40:30 -0700506 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700507 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700508 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700509 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700510 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700511 powerRestoreDelayIntf, powerRestoreDelayProp);
512
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700513 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700514 resp->byteLSB = delay;
515 resp->byteMSB = delay >> 8;
516
517 *dataLen = sizeof(GetPowerRestoreDelayRes);
518
519 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800520}
521
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800522static uint8_t bcdToDec(uint8_t val)
523{
524 return ((val / 16 * 10) + (val % 16));
525}
526
527// Allows an update utility or system BIOS to send the status of an embedded
528// firmware update attempt to the BMC. After received, BMC will create a logging
529// record.
530ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
531 uint8_t majorRevision,
532 uint8_t minorRevision,
533 uint32_t auxInfo)
534{
535 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700536 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800537 target = (target & selEvtTargetMask) >> selEvtTargetShift;
538
539 /* make sure the status is 0, 1, or 2 as per the spec */
540 if (status > 2)
541 {
542 return ipmi::response(ipmi::ccInvalidFieldRequest);
543 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700544 /* make sure the target is 0, 1, 2, or 4 as per the spec */
545 if (target > 4 || target == 3)
546 {
547 return ipmi::response(ipmi::ccInvalidFieldRequest);
548 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800549 /*orignal OEM command is to record OEM SEL.
550 But openbmc does not support OEM SEL, so we redirect it to redfish event
551 logging. */
552 std::string buildInfo;
553 std::string action;
554 switch (FWUpdateTarget(target))
555 {
556 case FWUpdateTarget::targetBMC:
557 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700558 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800559 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
560 " BuildID: " + std::to_string(auxInfo);
561 buildInfo += std::to_string(auxInfo);
562 break;
563 case FWUpdateTarget::targetBIOS:
564 firmware = "BIOS";
565 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700566 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800567 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
568 " minor: " +
569 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
570 " ReleaseNumber: " + // ASCII encoded
571 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
572 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
573 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
574 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
575 break;
576 case FWUpdateTarget::targetME:
577 firmware = "ME";
578 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700579 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800580 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
581 " minor2: " +
582 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
583 " build1: " +
584 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
585 " build2: " +
586 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
587 break;
588 case FWUpdateTarget::targetOEMEWS:
589 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700590 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800591 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
592 " BuildID: " + std::to_string(auxInfo);
593 break;
594 }
595
Jason M. Billsdc249272019-04-03 09:58:40 -0700596 static const std::string openBMCMessageRegistryVersion("0.1");
597 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
598
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800599 switch (status)
600 {
601 case 0x0:
602 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700603 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800604 break;
605 case 0x1:
606 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700607 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800608 break;
609 case 0x2:
610 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700611 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800612 break;
613 default:
614 action = "unknown";
615 break;
616 }
617
Jason M. Billsdc249272019-04-03 09:58:40 -0700618 std::string firmwareInstanceStr =
619 firmware + " instance: " + std::to_string(instance);
620 std::string message("[firmware update] " + firmwareInstanceStr +
621 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800622
623 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700624 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
625 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
626 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800627 return ipmi::responseSuccess();
628}
629
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530630ipmi::RspType<uint8_t, std::vector<uint8_t>>
631 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
632 uint2_t slotNumber, uint3_t baseBoardSlotNum,
633 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
634 uint8_t netFn, uint8_t cmd,
635 std::optional<std::vector<uint8_t>> writeData)
636{
637 if (reserved1 || reserved2)
638 {
639 return ipmi::responseInvalidFieldRequest();
640 }
641
642 boost::system::error_code ec;
643 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
644 std::vector<uint8_t>>;
645 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
646 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
647 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
648 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
649 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
650 *writeData);
651 if (ec)
652 {
653 phosphor::logging::log<phosphor::logging::level::ERR>(
654 "Failed to call dbus method SlotIpmbRequest");
655 return ipmi::responseUnspecifiedError();
656 }
657
658 std::vector<uint8_t> dataReceived(0);
659 int status = -1;
660 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
661
662 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
663
664 if (status)
665 {
666 phosphor::logging::log<phosphor::logging::level::ERR>(
667 "Failed to get response from SlotIpmbRequest");
668 return ipmi::responseResponseError();
669 }
670 return ipmi::responseSuccess(cc, dataReceived);
671}
672
Jason M. Bills64796042018-10-03 16:51:55 -0700673ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
674 ipmi_request_t request,
675 ipmi_response_t response,
676 ipmi_data_len_t dataLen,
677 ipmi_context_t context)
678{
679 SetPowerRestoreDelayReq* data =
680 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
681 uint16_t delay = 0;
682
683 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
684 {
685 *dataLen = 0;
686 return IPMI_CC_REQ_DATA_LEN_INVALID;
687 }
688 delay = data->byteMSB;
689 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700690 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700691 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700692 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
693 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700694 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
695 *dataLen = 0;
696
697 return IPMI_CC_OK;
698}
699
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700700static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700701{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700702 static constexpr const char* cpuPresencePathPrefix =
703 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
704 static constexpr const char* cpuPresenceIntf =
705 "xyz.openbmc_project.Inventory.Item";
706 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
707 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
708 try
Jason M. Bills64796042018-10-03 16:51:55 -0700709 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700710 auto service =
711 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
712
713 ipmi::Value result = ipmi::getDbusProperty(
714 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
715 return std::get<bool>(result);
716 }
717 catch (const std::exception& e)
718 {
719 phosphor::logging::log<phosphor::logging::level::INFO>(
720 "Cannot find processor presence",
721 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
722 return false;
723 }
724}
725
726ipmi::RspType<bool, // CATERR Reset Enabled
727 bool, // ERR2 Reset Enabled
728 uint6_t, // reserved
729 uint8_t, // reserved, returns 0x3F
730 uint6_t, // CPU1 CATERR Count
731 uint2_t, // CPU1 Status
732 uint6_t, // CPU2 CATERR Count
733 uint2_t, // CPU2 Status
734 uint6_t, // CPU3 CATERR Count
735 uint2_t, // CPU3 Status
736 uint6_t, // CPU4 CATERR Count
737 uint2_t, // CPU4 Status
738 uint8_t // Crashdump Count
739 >
740 ipmiOEMGetProcessorErrConfig()
741{
742 bool resetOnCATERR = false;
743 bool resetOnERR2 = false;
744 uint6_t cpu1CATERRCount = 0;
745 uint6_t cpu2CATERRCount = 0;
746 uint6_t cpu3CATERRCount = 0;
747 uint6_t cpu4CATERRCount = 0;
748 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700749 uint2_t cpu1Status = cpuPresent("CPU_1")
750 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
751 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
752 uint2_t cpu2Status = cpuPresent("CPU_2")
753 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
754 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
755 uint2_t cpu3Status = cpuPresent("CPU_3")
756 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
757 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
758 uint2_t cpu4Status = cpuPresent("CPU_4")
759 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
760 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700761
762 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
763 try
764 {
765 auto service = ipmi::getService(*busp, processorErrConfigIntf,
766 processorErrConfigObjPath);
767
768 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
769 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
770 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
771 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
772 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
773 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
774 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
775 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
776 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
777 }
778 catch (const std::exception& e)
779 {
780 phosphor::logging::log<phosphor::logging::level::ERR>(
781 "Failed to fetch processor error config",
782 phosphor::logging::entry("ERROR=%s", e.what()));
783 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700784 }
785
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700786 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
787 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
788 cpu2Status, cpu3CATERRCount, cpu3Status,
789 cpu4CATERRCount, cpu4Status, crashdumpCount);
790}
Jason M. Bills64796042018-10-03 16:51:55 -0700791
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700792ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
793 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
794 std::optional<bool> clearCPUErrorCount,
795 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
796{
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000797 if (reserved1 || reserved2)
798 {
799 return ipmi::responseInvalidFieldRequest();
800 }
801
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700802 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700803
804 try
805 {
Jayaprakash Mutyala0a652fa2021-07-01 17:09:39 +0000806 if (reserved3.value_or(0))
807 {
808 return ipmi::responseInvalidFieldRequest();
809 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700810 auto service = ipmi::getService(*busp, processorErrConfigIntf,
811 processorErrConfigObjPath);
812 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
813 processorErrConfigIntf, "ResetOnCATERR",
814 resetOnCATERR);
815 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
816 processorErrConfigIntf, "ResetOnERR2",
817 resetOnERR2);
818 if (clearCPUErrorCount.value_or(false))
819 {
820 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700821 processorErrConfigIntf, "ErrorCountCPU1",
822 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700823 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700824 processorErrConfigIntf, "ErrorCountCPU2",
825 static_cast<uint8_t>(0));
826 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
827 processorErrConfigIntf, "ErrorCountCPU3",
828 static_cast<uint8_t>(0));
829 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
830 processorErrConfigIntf, "ErrorCountCPU4",
831 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700832 }
833 if (clearCrashdumpCount.value_or(false))
834 {
835 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700836 processorErrConfigIntf, "CrashdumpCount",
837 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700838 }
Jason M. Bills64796042018-10-03 16:51:55 -0700839 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700840 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700841 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800842 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700843 "Failed to set processor error config",
844 phosphor::logging::entry("EXCEPTION=%s", e.what()));
845 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700846 }
847
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700848 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700849}
850
Yong Li703922d2018-11-06 13:25:31 +0800851ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
852 ipmi_request_t request,
853 ipmi_response_t response,
854 ipmi_data_len_t dataLen,
855 ipmi_context_t context)
856{
857 GetOEMShutdownPolicyRes* resp =
858 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
859
860 if (*dataLen != 0)
861 {
862 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800863 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800864 *dataLen = 0;
865 return IPMI_CC_REQ_DATA_LEN_INVALID;
866 }
867
868 *dataLen = 0;
869
870 try
871 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700872 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800873 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700874 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
875 Value variant = getDbusProperty(
876 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
877 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800878
879 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
880 convertPolicyFromString(std::get<std::string>(variant)) ==
881 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
882 NoShutdownOnOCOT)
883 {
884 resp->policy = 0;
885 }
886 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
887 convertPolicyFromString(std::get<std::string>(variant)) ==
888 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
889 Policy::ShutdownOnOCOT)
890 {
891 resp->policy = 1;
892 }
893 else
894 {
895 phosphor::logging::log<phosphor::logging::level::ERR>(
896 "oem_set_shutdown_policy: invalid property!",
897 phosphor::logging::entry(
898 "PROP=%s", std::get<std::string>(variant).c_str()));
899 return IPMI_CC_UNSPECIFIED_ERROR;
900 }
Yong Li703922d2018-11-06 13:25:31 +0800901 // TODO needs to check if it is multi-node products,
902 // policy is only supported on node 3/4
903 resp->policySupport = shutdownPolicySupported;
904 }
905 catch (sdbusplus::exception_t& e)
906 {
907 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
908 return IPMI_CC_UNSPECIFIED_ERROR;
909 }
910
911 *dataLen = sizeof(GetOEMShutdownPolicyRes);
912 return IPMI_CC_OK;
913}
914
915ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
916 ipmi_request_t request,
917 ipmi_response_t response,
918 ipmi_data_len_t dataLen,
919 ipmi_context_t context)
920{
921 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800922 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
923 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
924 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800925
926 // TODO needs to check if it is multi-node products,
927 // policy is only supported on node 3/4
928 if (*dataLen != 1)
929 {
930 phosphor::logging::log<phosphor::logging::level::ERR>(
931 "oem_set_shutdown_policy: invalid input len!");
932 *dataLen = 0;
933 return IPMI_CC_REQ_DATA_LEN_INVALID;
934 }
935
936 *dataLen = 0;
937 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
938 {
939 phosphor::logging::log<phosphor::logging::level::ERR>(
940 "oem_set_shutdown_policy: invalid input!");
941 return IPMI_CC_INVALID_FIELD_REQUEST;
942 }
943
Yong Li0669d192019-05-06 14:01:46 +0800944 if (*req == noShutdownOnOCOT)
945 {
946 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
947 Policy::NoShutdownOnOCOT;
948 }
949 else
950 {
951 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
952 Policy::ShutdownOnOCOT;
953 }
954
Yong Li703922d2018-11-06 13:25:31 +0800955 try
956 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700957 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800958 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700959 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800960 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700961 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800962 oemShutdownPolicyObjPathProp,
963 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800964 }
965 catch (sdbusplus::exception_t& e)
966 {
967 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
968 return IPMI_CC_UNSPECIFIED_ERROR;
969 }
970
971 return IPMI_CC_OK;
972}
973
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530974/** @brief implementation for check the DHCP or not in IPv4
975 * @param[in] Channel - Channel number
976 * @returns true or false.
977 */
978static bool isDHCPEnabled(uint8_t Channel)
979{
980 try
981 {
982 auto ethdevice = getChannelName(Channel);
983 if (ethdevice.empty())
984 {
985 return false;
986 }
987 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700988 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530989 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700990 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
991 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530992 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700993 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530994 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
995 {
996 return true;
997 }
998 else
999 {
1000 return false;
1001 }
1002 }
1003 catch (sdbusplus::exception_t& e)
1004 {
1005 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1006 return true;
1007 }
1008}
1009
1010/** @brief implementes for check the DHCP or not in IPv6
1011 * @param[in] Channel - Channel number
1012 * @returns true or false.
1013 */
1014static bool isDHCPIPv6Enabled(uint8_t Channel)
1015{
1016
1017 try
1018 {
1019 auto ethdevice = getChannelName(Channel);
1020 if (ethdevice.empty())
1021 {
1022 return false;
1023 }
1024 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001025 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301026 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001027 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1028 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301029 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001030 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301031 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1032 {
1033 return true;
1034 }
1035 else
1036 {
1037 return false;
1038 }
1039 }
1040 catch (sdbusplus::exception_t& e)
1041 {
1042 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1043 return true;
1044 }
1045}
1046
1047/** @brief implementes the creating of default new user
1048 * @param[in] userName - new username in 16 bytes.
1049 * @param[in] userPassword - new password in 20 bytes
1050 * @returns ipmi completion code.
1051 */
1052ipmi::RspType<> ipmiOEMSetUser2Activation(
1053 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1054 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1055{
1056 bool userState = false;
1057 // Check for System Interface not exist and LAN should be static
1058 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1059 {
Manish Baing440f62b2021-07-15 22:00:37 +00001060 ChannelInfo chInfo{};
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301061 try
1062 {
1063 getChannelInfo(channel, chInfo);
1064 }
1065 catch (sdbusplus::exception_t& e)
1066 {
1067 phosphor::logging::log<phosphor::logging::level::ERR>(
1068 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1069 phosphor::logging::entry("MSG: %s", e.description()));
1070 return ipmi::response(ipmi::ccUnspecifiedError);
1071 }
1072 if (chInfo.mediumType ==
1073 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1074 {
1075 phosphor::logging::log<phosphor::logging::level::ERR>(
1076 "ipmiOEMSetUser2Activation: system interface exist .");
1077 return ipmi::response(ipmi::ccCommandNotAvailable);
1078 }
1079 else
1080 {
1081
1082 if (chInfo.mediumType ==
1083 static_cast<uint8_t>(EChannelMediumType::lan8032))
1084 {
1085 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1086 {
1087 phosphor::logging::log<phosphor::logging::level::ERR>(
1088 "ipmiOEMSetUser2Activation: DHCP enabled .");
1089 return ipmi::response(ipmi::ccCommandNotAvailable);
1090 }
1091 }
1092 }
1093 }
1094 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1095 if (ipmi::ccSuccess ==
1096 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1097 {
1098 if (enabledUsers > 1)
1099 {
1100 phosphor::logging::log<phosphor::logging::level::ERR>(
1101 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1102 return ipmi::response(ipmi::ccCommandNotAvailable);
1103 }
1104 // Check the user 2 is enabled or not
1105 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1106 if (userState == true)
1107 {
1108 phosphor::logging::log<phosphor::logging::level::ERR>(
1109 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1110 return ipmi::response(ipmi::ccCommandNotAvailable);
1111 }
1112 }
1113 else
1114 {
1115 return ipmi::response(ipmi::ccUnspecifiedError);
1116 }
1117
1118#if BYTE_ORDER == LITTLE_ENDIAN
1119 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1120#endif
1121#if BYTE_ORDER == BIG_ENDIAN
1122 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1123#endif
1124
Vernon Mauery037cabd2020-05-14 12:16:01 -07001125 // ipmiUserSetUserName correctly handles char*, possibly non-null
1126 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001127 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1128 sizeof(userName));
1129 const std::string userNameRaw(
1130 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001131
Vernon Mauery037cabd2020-05-14 12:16:01 -07001132 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301133 {
1134 if (ipmi::ccSuccess ==
1135 ipmiUserSetUserPassword(
1136 ipmiDefaultUserId,
1137 reinterpret_cast<const char*>(userPassword.data())))
1138 {
1139 if (ipmi::ccSuccess ==
1140 ipmiUserSetPrivilegeAccess(
1141 ipmiDefaultUserId,
1142 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1143 privAccess, true))
1144 {
1145 phosphor::logging::log<phosphor::logging::level::INFO>(
1146 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001147 OPENSSL_cleanse(userPassword.data(), userPassword.size());
1148
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301149 return ipmi::responseSuccess();
1150 }
1151 }
1152 // we need to delete the default user id which added in this command as
1153 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001154 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301155 phosphor::logging::log<phosphor::logging::level::ERR>(
1156 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001157 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301158 }
1159 else
1160 {
1161 phosphor::logging::log<phosphor::logging::level::ERR>(
1162 "ipmiOEMSetUser2Activation: Setting username failed.");
1163 }
1164
1165 return ipmi::response(ipmi::ccCommandNotAvailable);
1166}
1167
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301168/** @brief implementes executing the linux command
1169 * @param[in] linux command
1170 * @returns status
1171 */
1172
1173static uint8_t executeCmd(const char* path)
1174{
1175 boost::process::child execProg(path);
1176 execProg.wait();
1177
1178 int retCode = execProg.exit_code();
1179 if (retCode)
1180 {
1181 return ipmi::ccUnspecifiedError;
1182 }
1183 return ipmi::ccSuccess;
1184}
1185
1186/** @brief implementes ASD Security event logging
1187 * @param[in] Event message string
1188 * @param[in] Event Severity
1189 * @returns status
1190 */
1191
1192static void atScaleDebugEventlog(std::string msg, int severity)
1193{
1194 std::string eventStr = "OpenBMC.0.1." + msg;
1195 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1196 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1197 eventStr.c_str(), NULL);
1198}
1199
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301200/** @brief implementes setting password for special user
1201 * @param[in] specialUserIndex
1202 * @param[in] userPassword - new password in 20 bytes
1203 * @returns ipmi completion code.
1204 */
1205ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1206 uint8_t specialUserIndex,
1207 std::vector<uint8_t> userPassword)
1208{
1209 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301210 ipmi_ret_t status = ipmi::ccSuccess;
1211
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301212 try
1213 {
1214 getChannelInfo(ctx->channel, chInfo);
1215 }
1216 catch (sdbusplus::exception_t& e)
1217 {
1218 phosphor::logging::log<phosphor::logging::level::ERR>(
1219 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1220 phosphor::logging::entry("MSG: %s", e.description()));
1221 return ipmi::responseUnspecifiedError();
1222 }
1223 if (chInfo.mediumType !=
1224 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1225 {
1226 phosphor::logging::log<phosphor::logging::level::ERR>(
1227 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1228 "interface");
1229 return ipmi::responseCommandNotAvailable();
1230 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301231
1232 // 0 for root user and 1 for AtScaleDebug is allowed
1233 if (specialUserIndex >
1234 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301235 {
1236 phosphor::logging::log<phosphor::logging::level::ERR>(
1237 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1238 return ipmi::responseParmOutOfRange();
1239 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301240 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301241 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301242 constexpr uint8_t minPasswordSizeRequired = 6;
1243 std::string passwd;
1244 if (userPassword.size() < minPasswordSizeRequired ||
1245 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1246 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001247 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301248 return ipmi::responseReqDataLenInvalid();
1249 }
1250 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1251 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001252 // Clear sensitive data
1253 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301254 if (specialUserIndex ==
1255 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1256 {
1257 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1258
1259 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1260 }
1261 else
1262 {
1263 status = ipmiSetSpecialUserPassword("root", passwd);
1264 }
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001265 // Clear sensitive data
1266 OPENSSL_cleanse(&passwd, passwd.length());
1267
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301268 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301269 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301270 else
1271 {
1272 if (specialUserIndex ==
1273 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1274 {
1275 status = executeCmd("passwd -d root");
1276 }
1277 else
1278 {
1279
1280 status = executeCmd("passwd -d asdbg");
1281
1282 if (status == 0)
1283 {
1284 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1285 LOG_INFO);
1286 }
1287 }
1288 return ipmi::response(status);
1289 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301290}
1291
Kuiying Wang45f04982018-12-26 09:23:08 +08001292namespace ledAction
1293{
1294using namespace sdbusplus::xyz::openbmc_project::Led::server;
1295std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001296 {Physical::Action::Off, 0},
1297 {Physical::Action::On, 2},
1298 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001299
1300std::map<uint8_t, std::string> offsetObjPath = {
1301 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1302
1303} // namespace ledAction
1304
1305int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1306 const std::string& objPath, uint8_t& state)
1307{
1308 try
1309 {
1310 std::string service = getService(bus, intf, objPath);
1311 Value stateValue =
1312 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001313 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001314 state = ledAction::actionDbusToIpmi.at(
1315 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1316 convertActionFromString(strState));
1317 }
1318 catch (sdbusplus::exception::SdBusError& e)
1319 {
1320 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1321 return -1;
1322 }
1323 return 0;
1324}
1325
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001326ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001327{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001328 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001329 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001330 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001331 for (auto it = ledAction::offsetObjPath.begin();
1332 it != ledAction::offsetObjPath.end(); ++it)
1333 {
1334 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001335 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001336 {
1337 phosphor::logging::log<phosphor::logging::level::ERR>(
1338 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001339 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001340 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001341 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001342 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001343 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001344}
1345
Yong Li23737fe2019-02-19 08:49:55 +08001346ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1347 ipmi_request_t request,
1348 ipmi_response_t response,
1349 ipmi_data_len_t dataLen,
1350 ipmi_context_t context)
1351{
1352 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1353 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1354
1355 if (*dataLen == 0)
1356 {
1357 phosphor::logging::log<phosphor::logging::level::ERR>(
1358 "CfgHostSerial: invalid input len!",
1359 phosphor::logging::entry("LEN=%d", *dataLen));
1360 return IPMI_CC_REQ_DATA_LEN_INVALID;
1361 }
1362
1363 switch (req->command)
1364 {
1365 case getHostSerialCfgCmd:
1366 {
1367 if (*dataLen != 1)
1368 {
1369 phosphor::logging::log<phosphor::logging::level::ERR>(
1370 "CfgHostSerial: invalid input len!");
1371 *dataLen = 0;
1372 return IPMI_CC_REQ_DATA_LEN_INVALID;
1373 }
1374
1375 *dataLen = 0;
1376
1377 boost::process::ipstream is;
1378 std::vector<std::string> data;
1379 std::string line;
1380 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1381 boost::process::std_out > is);
1382
1383 while (c1.running() && std::getline(is, line) && !line.empty())
1384 {
1385 data.push_back(line);
1386 }
1387
1388 c1.wait();
1389 if (c1.exit_code())
1390 {
1391 phosphor::logging::log<phosphor::logging::level::ERR>(
1392 "CfgHostSerial:: error on execute",
1393 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1394 // Using the default value
1395 *resp = 0;
1396 }
1397 else
1398 {
1399 if (data.size() != 1)
1400 {
1401 phosphor::logging::log<phosphor::logging::level::ERR>(
1402 "CfgHostSerial:: error on read env");
1403 return IPMI_CC_UNSPECIFIED_ERROR;
1404 }
1405 try
1406 {
1407 unsigned long tmp = std::stoul(data[0]);
1408 if (tmp > std::numeric_limits<uint8_t>::max())
1409 {
1410 throw std::out_of_range("Out of range");
1411 }
1412 *resp = static_cast<uint8_t>(tmp);
1413 }
1414 catch (const std::invalid_argument& e)
1415 {
1416 phosphor::logging::log<phosphor::logging::level::ERR>(
1417 "invalid config ",
1418 phosphor::logging::entry("ERR=%s", e.what()));
1419 return IPMI_CC_UNSPECIFIED_ERROR;
1420 }
1421 catch (const std::out_of_range& e)
1422 {
1423 phosphor::logging::log<phosphor::logging::level::ERR>(
1424 "out_of_range config ",
1425 phosphor::logging::entry("ERR=%s", e.what()));
1426 return IPMI_CC_UNSPECIFIED_ERROR;
1427 }
1428 }
1429
1430 *dataLen = 1;
1431 break;
1432 }
1433 case setHostSerialCfgCmd:
1434 {
1435 if (*dataLen != sizeof(CfgHostSerialReq))
1436 {
1437 phosphor::logging::log<phosphor::logging::level::ERR>(
1438 "CfgHostSerial: invalid input len!");
1439 *dataLen = 0;
1440 return IPMI_CC_REQ_DATA_LEN_INVALID;
1441 }
1442
1443 *dataLen = 0;
1444
1445 if (req->parameter > HostSerialCfgParamMax)
1446 {
1447 phosphor::logging::log<phosphor::logging::level::ERR>(
1448 "CfgHostSerial: invalid input!");
1449 return IPMI_CC_INVALID_FIELD_REQUEST;
1450 }
1451
1452 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1453 std::to_string(req->parameter));
1454
1455 c1.wait();
1456 if (c1.exit_code())
1457 {
1458 phosphor::logging::log<phosphor::logging::level::ERR>(
1459 "CfgHostSerial:: error on execute",
1460 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1461 return IPMI_CC_UNSPECIFIED_ERROR;
1462 }
1463 break;
1464 }
1465 default:
1466 phosphor::logging::log<phosphor::logging::level::ERR>(
1467 "CfgHostSerial: invalid input!");
1468 *dataLen = 0;
1469 return IPMI_CC_INVALID_FIELD_REQUEST;
1470 }
1471
1472 return IPMI_CC_OK;
1473}
1474
James Feist91244a62019-02-19 15:04:54 -08001475constexpr const char* thermalModeInterface =
1476 "xyz.openbmc_project.Control.ThermalMode";
1477constexpr const char* thermalModePath =
1478 "/xyz/openbmc_project/control/thermal_mode";
1479
1480bool getFanProfileInterface(
1481 sdbusplus::bus::bus& bus,
1482 boost::container::flat_map<
1483 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1484{
1485 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1486 "GetAll");
1487 call.append(thermalModeInterface);
1488 try
1489 {
1490 auto data = bus.call(call);
1491 data.read(resp);
1492 }
1493 catch (sdbusplus::exception_t& e)
1494 {
1495 phosphor::logging::log<phosphor::logging::level::ERR>(
1496 "getFanProfileInterface: can't get thermal mode!",
1497 phosphor::logging::entry("ERR=%s", e.what()));
1498 return false;
1499 }
1500 return true;
1501}
1502
anil kumar appanaf945eee2019-09-25 23:29:11 +00001503/**@brief implements the OEM set fan config.
1504 * @param selectedFanProfile - fan profile to enable
1505 * @param reserved1
1506 * @param performanceMode - Performance/Acoustic mode
1507 * @param reserved2
1508 * @param setPerformanceMode - set Performance/Acoustic mode
1509 * @param setFanProfile - set fan profile
1510 *
1511 * @return IPMI completion code.
1512 **/
1513ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1514
1515 uint2_t reserved1, bool performanceMode,
1516 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301517 bool setFanProfile,
1518 std::optional<uint8_t> dimmGroupId,
1519 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001520{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001521 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001522 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001523 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001524 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301525
1526 if (dimmGroupId)
1527 {
1528 if (*dimmGroupId >= maxCPUNum)
1529 {
1530 return ipmi::responseInvalidFieldRequest();
1531 }
1532 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1533 {
1534 return ipmi::responseInvalidFieldRequest();
1535 }
1536 }
1537
James Feist91244a62019-02-19 15:04:54 -08001538 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001539 boost::container::flat_map<
1540 std::string, std::variant<std::vector<std::string>, std::string>>
1541 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001542 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1543 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001544 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001545 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001546 }
1547
1548 std::vector<std::string>* supported =
1549 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1550 if (supported == nullptr)
1551 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001552 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001553 }
1554 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001555 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001556 {
James Feist91244a62019-02-19 15:04:54 -08001557 if (performanceMode)
1558 {
1559
1560 if (std::find(supported->begin(), supported->end(),
1561 "Performance") != supported->end())
1562 {
1563 mode = "Performance";
1564 }
1565 }
1566 else
1567 {
James Feist91244a62019-02-19 15:04:54 -08001568 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1569 supported->end())
1570 {
1571 mode = "Acoustic";
1572 }
1573 }
1574 if (mode.empty())
1575 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001576 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001577 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001578
1579 try
1580 {
1581 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1582 thermalModeInterface, "Current", mode);
1583 }
1584 catch (sdbusplus::exception_t& e)
1585 {
1586 phosphor::logging::log<phosphor::logging::level::ERR>(
1587 "ipmiOEMSetFanConfig: can't set thermal mode!",
1588 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1589 return ipmi::responseResponseError();
1590 }
James Feist91244a62019-02-19 15:04:54 -08001591 }
1592
anil kumar appanaf945eee2019-09-25 23:29:11 +00001593 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001594}
1595
James Feist5b693632019-07-09 09:06:09 -07001596ipmi::RspType<uint8_t, // profile support map
1597 uint8_t, // fan control profile enable
1598 uint8_t, // flags
1599 uint32_t // dimm presence bit map
1600 >
1601 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001602{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301603 if (dimmGroupId >= maxCPUNum)
1604 {
1605 return ipmi::responseInvalidFieldRequest();
1606 }
1607
1608 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1609
1610 if (!cpuStatus)
1611 {
1612 return ipmi::responseInvalidFieldRequest();
1613 }
1614
James Feist91244a62019-02-19 15:04:54 -08001615 boost::container::flat_map<
1616 std::string, std::variant<std::vector<std::string>, std::string>>
1617 profileData;
1618
Vernon Mauery15419dd2019-05-24 09:40:30 -07001619 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1620 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001621 {
James Feist5b693632019-07-09 09:06:09 -07001622 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001623 }
1624
1625 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1626
1627 if (current == nullptr)
1628 {
1629 phosphor::logging::log<phosphor::logging::level::ERR>(
1630 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001631 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001632 }
1633 bool performance = (*current == "Performance");
1634
James Feist5b693632019-07-09 09:06:09 -07001635 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001636 if (performance)
1637 {
James Feist5b693632019-07-09 09:06:09 -07001638 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001639 }
1640
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001641 constexpr uint8_t fanControlDefaultProfile = 0x80;
1642 constexpr uint8_t fanControlProfileState = 0x00;
1643 constexpr uint32_t dimmPresenceBitmap = 0x00;
1644
1645 return ipmi::responseSuccess(fanControlDefaultProfile,
1646 fanControlProfileState, flags,
1647 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001648}
James Feist5f957ca2019-03-14 15:33:55 -07001649constexpr const char* cfmLimitSettingPath =
1650 "/xyz/openbmc_project/control/cfm_limit";
1651constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001652constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001653constexpr const size_t legacyPCHSensorNumber = 0x22;
1654constexpr const char* exitAirPathName = "Exit_Air";
1655constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001656constexpr const char* pidConfigurationIface =
1657 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001658
James Feist09f6b602019-08-08 11:30:03 -07001659static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001660{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001661 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001662 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001663 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1664 "/xyz/openbmc_project/object_mapper",
1665 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001666
James Feistacc8a4e2019-04-02 14:23:57 -07001667 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001668 std::string path;
1669 GetSubTreeType resp;
1670 try
1671 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001672 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001673 reply.read(resp);
1674 }
1675 catch (sdbusplus::exception_t&)
1676 {
1677 phosphor::logging::log<phosphor::logging::level::ERR>(
1678 "ipmiOEMGetFscParameter: mapper error");
1679 };
James Feist09f6b602019-08-08 11:30:03 -07001680 auto config =
1681 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1682 return pair.first.find(name) != std::string::npos;
1683 });
James Feistfaa4f222019-03-21 16:21:55 -07001684 if (config != resp.end())
1685 {
1686 path = std::move(config->first);
1687 }
1688 return path;
1689}
James Feist5f957ca2019-03-14 15:33:55 -07001690
James Feistacc8a4e2019-04-02 14:23:57 -07001691// flat map to make alphabetical
1692static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1693{
1694 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001695 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001696 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001697 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1698 "/xyz/openbmc_project/object_mapper",
1699 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001700
1701 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1702 GetSubTreeType resp;
1703
1704 try
1705 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001706 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001707 reply.read(resp);
1708 }
1709 catch (sdbusplus::exception_t&)
1710 {
1711 phosphor::logging::log<phosphor::logging::level::ERR>(
1712 "getFanConfigPaths: mapper error");
1713 };
1714 for (const auto& [path, objects] : resp)
1715 {
1716 if (objects.empty())
1717 {
1718 continue; // should be impossible
1719 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001720
1721 try
1722 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001723 ret.emplace(path,
1724 getAllDbusProperties(*dbus, objects[0].first, path,
1725 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001726 }
1727 catch (sdbusplus::exception_t& e)
1728 {
1729 phosphor::logging::log<phosphor::logging::level::ERR>(
1730 "getPidConfigs: can't get DbusProperties!",
1731 phosphor::logging::entry("ERR=%s", e.what()));
1732 }
James Feistacc8a4e2019-04-02 14:23:57 -07001733 }
1734 return ret;
1735}
1736
1737ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1738{
1739 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1740 if (data.empty())
1741 {
1742 return ipmi::responseResponseError();
1743 }
1744 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1745 for (const auto& [_, pid] : data)
1746 {
1747 auto findClass = pid.find("Class");
1748 if (findClass == pid.end())
1749 {
1750 phosphor::logging::log<phosphor::logging::level::ERR>(
1751 "ipmiOEMGetFscParameter: found illegal pid "
1752 "configurations");
1753 return ipmi::responseResponseError();
1754 }
1755 std::string type = std::get<std::string>(findClass->second);
1756 if (type == "fan")
1757 {
1758 auto findOutLimit = pid.find("OutLimitMin");
1759 if (findOutLimit == pid.end())
1760 {
1761 phosphor::logging::log<phosphor::logging::level::ERR>(
1762 "ipmiOEMGetFscParameter: found illegal pid "
1763 "configurations");
1764 return ipmi::responseResponseError();
1765 }
1766 // get the min out of all the offsets
1767 minOffset = std::min(
1768 minOffset,
1769 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1770 }
1771 }
1772 if (minOffset == std::numeric_limits<uint8_t>::max())
1773 {
1774 phosphor::logging::log<phosphor::logging::level::ERR>(
1775 "ipmiOEMGetFscParameter: found no fan configurations!");
1776 return ipmi::responseResponseError();
1777 }
1778
1779 return ipmi::responseSuccess(minOffset);
1780}
1781
1782ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1783{
1784 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1785 if (data.empty())
1786 {
1787
1788 phosphor::logging::log<phosphor::logging::level::ERR>(
1789 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1790 return ipmi::responseResponseError();
1791 }
1792
Vernon Mauery15419dd2019-05-24 09:40:30 -07001793 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001794 bool found = false;
1795 for (const auto& [path, pid] : data)
1796 {
1797 auto findClass = pid.find("Class");
1798 if (findClass == pid.end())
1799 {
1800
1801 phosphor::logging::log<phosphor::logging::level::ERR>(
1802 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1803 "configurations");
1804 return ipmi::responseResponseError();
1805 }
1806 std::string type = std::get<std::string>(findClass->second);
1807 if (type == "fan")
1808 {
1809 auto findOutLimit = pid.find("OutLimitMin");
1810 if (findOutLimit == pid.end())
1811 {
1812
1813 phosphor::logging::log<phosphor::logging::level::ERR>(
1814 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1815 "configurations");
1816 return ipmi::responseResponseError();
1817 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001818 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001819 path, pidConfigurationIface, "OutLimitMin",
1820 static_cast<double>(offset));
1821 found = true;
1822 }
1823 }
1824 if (!found)
1825 {
1826 phosphor::logging::log<phosphor::logging::level::ERR>(
1827 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1828 return ipmi::responseResponseError();
1829 }
1830
1831 return ipmi::responseSuccess();
1832}
1833
1834ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1835 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001836{
1837 constexpr const size_t disableLimiting = 0x0;
1838
Vernon Mauery15419dd2019-05-24 09:40:30 -07001839 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001840 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001841 {
James Feist09f6b602019-08-08 11:30:03 -07001842 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001843 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001844 {
James Feist09f6b602019-08-08 11:30:03 -07001845 pathName = exitAirPathName;
1846 }
1847 else if (param1 == legacyPCHSensorNumber)
1848 {
1849 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001850 }
1851 else
1852 {
James Feistacc8a4e2019-04-02 14:23:57 -07001853 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001854 }
James Feist09f6b602019-08-08 11:30:03 -07001855 std::string path = getConfigPath(pathName);
1856 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1857 pidConfigurationIface, "SetPoint",
1858 static_cast<double>(param2));
1859 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001860 }
James Feistacc8a4e2019-04-02 14:23:57 -07001861 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001862 {
James Feistacc8a4e2019-04-02 14:23:57 -07001863 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001864
1865 // must be greater than 50 based on eps
1866 if (cfm < 50 && cfm != disableLimiting)
1867 {
James Feistacc8a4e2019-04-02 14:23:57 -07001868 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001869 }
1870
1871 try
1872 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001873 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001874 cfmLimitIface, "Limit",
1875 static_cast<double>(cfm));
1876 }
1877 catch (sdbusplus::exception_t& e)
1878 {
1879 phosphor::logging::log<phosphor::logging::level::ERR>(
1880 "ipmiOEMSetFscParameter: can't set cfm setting!",
1881 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001882 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001883 }
James Feistacc8a4e2019-04-02 14:23:57 -07001884 return ipmi::responseSuccess();
1885 }
1886 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1887 {
1888 constexpr const size_t maxDomainCount = 8;
1889 uint8_t requestedDomainMask = param1;
1890 boost::container::flat_map data = getPidConfigs();
1891 if (data.empty())
1892 {
1893
1894 phosphor::logging::log<phosphor::logging::level::ERR>(
1895 "ipmiOEMSetFscParameter: found no pid configurations!");
1896 return ipmi::responseResponseError();
1897 }
1898 size_t count = 0;
1899 for (const auto& [path, pid] : data)
1900 {
1901 auto findClass = pid.find("Class");
1902 if (findClass == pid.end())
1903 {
1904
1905 phosphor::logging::log<phosphor::logging::level::ERR>(
1906 "ipmiOEMSetFscParameter: found illegal pid "
1907 "configurations");
1908 return ipmi::responseResponseError();
1909 }
1910 std::string type = std::get<std::string>(findClass->second);
1911 if (type == "fan")
1912 {
1913 if (requestedDomainMask & (1 << count))
1914 {
1915 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001916 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001917 pidConfigurationIface, "OutLimitMax",
1918 static_cast<double>(param2));
1919 }
1920 count++;
1921 }
1922 }
1923 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001924 }
1925 else
1926 {
1927 // todo other command parts possibly
1928 // tcontrol is handled in peci now
1929 // fan speed offset not implemented yet
1930 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001931 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001932 }
1933}
1934
James Feistacc8a4e2019-04-02 14:23:57 -07001935ipmi::RspType<
1936 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1937 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001938{
James Feist09f6b602019-08-08 11:30:03 -07001939 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001940
Vernon Mauery15419dd2019-05-24 09:40:30 -07001941 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001942 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001943 {
James Feistacc8a4e2019-04-02 14:23:57 -07001944 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001945 {
James Feistacc8a4e2019-04-02 14:23:57 -07001946 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001947 }
1948
James Feist09f6b602019-08-08 11:30:03 -07001949 std::string pathName;
1950
1951 if (*param == legacyExitAirSensorNumber)
1952 {
1953 pathName = exitAirPathName;
1954 }
1955 else if (*param == legacyPCHSensorNumber)
1956 {
1957 pathName = pchPathName;
1958 }
1959 else
James Feistfaa4f222019-03-21 16:21:55 -07001960 {
James Feistacc8a4e2019-04-02 14:23:57 -07001961 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001962 }
James Feist09f6b602019-08-08 11:30:03 -07001963
1964 uint8_t setpoint = legacyDefaultSetpoint;
1965 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001966 if (path.size())
1967 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001968 Value val = ipmi::getDbusProperty(
1969 *dbus, "xyz.openbmc_project.EntityManager", path,
1970 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001971 setpoint = std::floor(std::get<double>(val) + 0.5);
1972 }
1973
1974 // old implementation used to return the "default" and current, we
1975 // don't make the default readily available so just make both the
1976 // same
James Feistfaa4f222019-03-21 16:21:55 -07001977
James Feistacc8a4e2019-04-02 14:23:57 -07001978 return ipmi::responseSuccess(
1979 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001980 }
James Feistacc8a4e2019-04-02 14:23:57 -07001981 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1982 {
1983 constexpr const size_t maxDomainCount = 8;
1984
1985 if (!param)
1986 {
1987 return ipmi::responseReqDataLenInvalid();
1988 }
1989 uint8_t requestedDomain = *param;
1990 if (requestedDomain >= maxDomainCount)
1991 {
1992 return ipmi::responseInvalidFieldRequest();
1993 }
1994
1995 boost::container::flat_map data = getPidConfigs();
1996 if (data.empty())
1997 {
1998 phosphor::logging::log<phosphor::logging::level::ERR>(
1999 "ipmiOEMGetFscParameter: found no pid configurations!");
2000 return ipmi::responseResponseError();
2001 }
2002 size_t count = 0;
2003 for (const auto& [_, pid] : data)
2004 {
2005 auto findClass = pid.find("Class");
2006 if (findClass == pid.end())
2007 {
2008 phosphor::logging::log<phosphor::logging::level::ERR>(
2009 "ipmiOEMGetFscParameter: found illegal pid "
2010 "configurations");
2011 return ipmi::responseResponseError();
2012 }
2013 std::string type = std::get<std::string>(findClass->second);
2014 if (type == "fan")
2015 {
2016 if (requestedDomain == count)
2017 {
2018 auto findOutLimit = pid.find("OutLimitMax");
2019 if (findOutLimit == pid.end())
2020 {
2021 phosphor::logging::log<phosphor::logging::level::ERR>(
2022 "ipmiOEMGetFscParameter: found illegal pid "
2023 "configurations");
2024 return ipmi::responseResponseError();
2025 }
2026
2027 return ipmi::responseSuccess(
2028 static_cast<uint8_t>(std::floor(
2029 std::get<double>(findOutLimit->second) + 0.5)));
2030 }
2031 else
2032 {
2033 count++;
2034 }
2035 }
2036 }
2037
2038 return ipmi::responseInvalidFieldRequest();
2039 }
2040 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002041 {
2042
2043 /*
2044 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002045 previous behavior didn't seem to prevent this, ignore the check for
2046 now.
James Feist5f957ca2019-03-14 15:33:55 -07002047
James Feistacc8a4e2019-04-02 14:23:57 -07002048 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002049 {
2050 phosphor::logging::log<phosphor::logging::level::ERR>(
2051 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002052 return IPMI_CC_REQ_DATA_LEN_INVALID;
2053 }
2054 */
2055 Value cfmLimit;
2056 Value cfmMaximum;
2057 try
2058 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002059 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002060 cfmLimitSettingPath, cfmLimitIface,
2061 "Limit");
2062 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002063 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002064 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2065 }
2066 catch (sdbusplus::exception_t& e)
2067 {
2068 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002069 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002070 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002071 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002072 }
2073
James Feistacc8a4e2019-04-02 14:23:57 -07002074 double cfmMax = std::get<double>(cfmMaximum);
2075 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002076
James Feistacc8a4e2019-04-02 14:23:57 -07002077 cfmLim = std::floor(cfmLim + 0.5);
2078 cfmMax = std::floor(cfmMax + 0.5);
2079 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2080 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002081
James Feistacc8a4e2019-04-02 14:23:57 -07002082 return ipmi::responseSuccess(
2083 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002084 }
James Feistacc8a4e2019-04-02 14:23:57 -07002085
James Feist5f957ca2019-03-14 15:33:55 -07002086 else
2087 {
2088 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002089 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002090 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002091 }
2092}
2093
Cheng C Yang773703a2019-08-15 09:41:11 +08002094using crConfigVariant =
2095 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2096
2097int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2098 const crConfigVariant& value,
2099 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2100{
2101 boost::system::error_code ec;
2102 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002103 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002104 "/xyz/openbmc_project/control/power_supply_redundancy",
2105 "org.freedesktop.DBus.Properties", "Set",
2106 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2107 if (ec)
2108 {
2109 phosphor::logging::log<phosphor::logging::level::ERR>(
2110 "Failed to set dbus property to cold redundancy");
2111 return -1;
2112 }
2113
2114 return 0;
2115}
2116
Kuiying Wange45333a2020-07-22 22:06:37 +08002117int getCRConfig(
2118 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2119 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2120 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002121{
2122 boost::system::error_code ec;
2123 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002124 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002125 "/xyz/openbmc_project/control/power_supply_redundancy",
2126 "org.freedesktop.DBus.Properties", "Get",
2127 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2128 if (ec)
2129 {
2130 phosphor::logging::log<phosphor::logging::level::ERR>(
2131 "Failed to get dbus property to cold redundancy");
2132 return -1;
2133 }
2134 return 0;
2135}
2136
2137uint8_t getPSUCount(void)
2138{
2139 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2140 ipmi::Value num;
2141 try
2142 {
2143 num = ipmi::getDbusProperty(
2144 *dbus, "xyz.openbmc_project.PSURedundancy",
2145 "/xyz/openbmc_project/control/power_supply_redundancy",
2146 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2147 }
2148 catch (sdbusplus::exception_t& e)
2149 {
2150 phosphor::logging::log<phosphor::logging::level::ERR>(
2151 "Failed to get PSUNumber property from dbus interface");
2152 return 0;
2153 }
2154 uint8_t* pNum = std::get_if<uint8_t>(&num);
2155 if (!pNum)
2156 {
2157 phosphor::logging::log<phosphor::logging::level::ERR>(
2158 "Error to get PSU Number");
2159 return 0;
2160 }
2161 return *pNum;
2162}
2163
2164bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2165{
2166 if (conf.size() < num)
2167 {
2168 phosphor::logging::log<phosphor::logging::level::ERR>(
2169 "Invalid PSU Ranking");
2170 return false;
2171 }
2172 std::set<uint8_t> confSet;
2173 for (uint8_t i = 0; i < num; i++)
2174 {
2175 if (conf[i] > num)
2176 {
2177 phosphor::logging::log<phosphor::logging::level::ERR>(
2178 "PSU Ranking is larger than current PSU number");
2179 return false;
2180 }
2181 confSet.emplace(conf[i]);
2182 }
2183
2184 if (confSet.size() != num)
2185 {
2186 phosphor::logging::log<phosphor::logging::level::ERR>(
2187 "duplicate PSU Ranking");
2188 return false;
2189 }
2190 return true;
2191}
2192
2193enum class crParameter
2194{
2195 crStatus = 0,
2196 crFeature = 1,
2197 rotationFeature = 2,
2198 rotationAlgo = 3,
2199 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002200 numOfPSU = 5,
2201 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002202};
2203
2204constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2205static const constexpr uint32_t oneDay = 0x15180;
2206static const constexpr uint32_t oneMonth = 0xf53700;
2207static const constexpr uint8_t userSpecific = 0x01;
2208static const constexpr uint8_t crSetCompleted = 0;
2209ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2210 uint8_t parameter,
2211 ipmi::message::Payload& payload)
2212{
2213 switch (static_cast<crParameter>(parameter))
2214 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002215 case crParameter::rotationFeature:
2216 {
2217 uint8_t param1;
2218 if (payload.unpack(param1) || !payload.fullyUnpacked())
2219 {
2220 return ipmi::responseReqDataLenInvalid();
2221 }
2222 // Rotation Enable can only be true or false
2223 if (param1 > 1)
2224 {
2225 return ipmi::responseInvalidFieldRequest();
2226 }
2227 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2228 {
2229 return ipmi::responseResponseError();
2230 }
2231 break;
2232 }
2233 case crParameter::rotationAlgo:
2234 {
2235 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2236 std::string algoName;
2237 uint8_t param1;
2238 if (payload.unpack(param1))
2239 {
2240 return ipmi::responseReqDataLenInvalid();
2241 }
2242 switch (param1)
2243 {
2244 case 0:
2245 algoName = "xyz.openbmc_project.Control."
2246 "PowerSupplyRedundancy.Algo.bmcSpecific";
2247 break;
2248 case 1:
2249 algoName = "xyz.openbmc_project.Control."
2250 "PowerSupplyRedundancy.Algo.userSpecific";
2251 break;
2252 default:
2253 return ipmi::responseInvalidFieldRequest();
2254 }
2255 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2256 {
2257 return ipmi::responseResponseError();
2258 }
2259
2260 uint8_t numberOfPSU = getPSUCount();
2261 if (!numberOfPSU)
2262 {
2263 return ipmi::responseResponseError();
2264 }
2265 std::vector<uint8_t> rankOrder;
2266
2267 if (param1 == userSpecific)
2268 {
2269 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2270 {
2271 ipmi::responseReqDataLenInvalid();
2272 }
Yong Li83315132019-10-23 17:42:24 +08002273 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002274 {
2275 return ipmi::responseReqDataLenInvalid();
2276 }
2277
2278 if (!validateCRAlgo(rankOrder, numberOfPSU))
2279 {
2280 return ipmi::responseInvalidFieldRequest();
2281 }
2282 }
2283 else
2284 {
2285 if (rankOrder.size() > 0)
2286 {
2287 return ipmi::responseReqDataLenInvalid();
2288 }
2289 for (uint8_t i = 1; i <= numberOfPSU; i++)
2290 {
2291 rankOrder.emplace_back(i);
2292 }
2293 }
2294 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2295 {
2296 return ipmi::responseResponseError();
2297 }
2298 break;
2299 }
2300 case crParameter::rotationPeriod:
2301 {
2302 // Minimum Rotation period is One day (86400 seconds) and Max
2303 // Rotation Period is 6 month (0xf53700 seconds)
2304 uint32_t period;
2305 if (payload.unpack(period) || !payload.fullyUnpacked())
2306 {
2307 return ipmi::responseReqDataLenInvalid();
2308 }
2309 if ((period < oneDay) || (period > oneMonth))
2310 {
2311 return ipmi::responseInvalidFieldRequest();
2312 }
2313 if (setCRConfig(ctx, "PeriodOfRotation", period))
2314 {
2315 return ipmi::responseResponseError();
2316 }
2317 break;
2318 }
2319 default:
2320 {
2321 return ipmi::response(ccParameterNotSupported);
2322 }
2323 }
2324
Cheng C Yang773703a2019-08-15 09:41:11 +08002325 return ipmi::responseSuccess(crSetCompleted);
2326}
2327
Yong Li83315132019-10-23 17:42:24 +08002328ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002329 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2330{
2331 crConfigVariant value;
2332 switch (static_cast<crParameter>(parameter))
2333 {
2334 case crParameter::crStatus:
2335 {
2336 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2337 {
2338 return ipmi::responseResponseError();
2339 }
2340 std::string* pStatus = std::get_if<std::string>(&value);
2341 if (!pStatus)
2342 {
2343 phosphor::logging::log<phosphor::logging::level::ERR>(
2344 "Error to get ColdRedundancyStatus property");
2345 return ipmi::responseResponseError();
2346 }
2347 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2348 auto status =
2349 server::PowerSupplyRedundancy::convertStatusFromString(
2350 *pStatus);
2351 switch (status)
2352 {
2353 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002354 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002355 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002356
2357 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002358 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002359 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002360 default:
2361 phosphor::logging::log<phosphor::logging::level::ERR>(
2362 "Error to get valid status");
2363 return ipmi::responseResponseError();
2364 }
2365 }
2366 case crParameter::crFeature:
2367 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002368 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002369 {
2370 return ipmi::responseResponseError();
2371 }
2372 bool* pResponse = std::get_if<bool>(&value);
2373 if (!pResponse)
2374 {
2375 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002376 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002377 return ipmi::responseResponseError();
2378 }
2379
Cheng C Yangf41e3342019-09-10 04:47:23 +08002380 return ipmi::responseSuccess(parameter,
2381 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002382 }
2383 case crParameter::rotationFeature:
2384 {
2385 if (getCRConfig(ctx, "RotationEnabled", value))
2386 {
2387 return ipmi::responseResponseError();
2388 }
2389 bool* pResponse = std::get_if<bool>(&value);
2390 if (!pResponse)
2391 {
2392 phosphor::logging::log<phosphor::logging::level::ERR>(
2393 "Error to get RotationEnabled property");
2394 return ipmi::responseResponseError();
2395 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002396 return ipmi::responseSuccess(parameter,
2397 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002398 }
2399 case crParameter::rotationAlgo:
2400 {
2401 if (getCRConfig(ctx, "RotationAlgorithm", value))
2402 {
2403 return ipmi::responseResponseError();
2404 }
2405
2406 std::string* pAlgo = std::get_if<std::string>(&value);
2407 if (!pAlgo)
2408 {
2409 phosphor::logging::log<phosphor::logging::level::ERR>(
2410 "Error to get RotationAlgorithm property");
2411 return ipmi::responseResponseError();
2412 }
Yong Li83315132019-10-23 17:42:24 +08002413 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002414 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2415 auto algo =
2416 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002417
Cheng C Yang773703a2019-08-15 09:41:11 +08002418 switch (algo)
2419 {
2420 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002421 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002422 break;
2423 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002424 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002425 break;
2426 default:
2427 phosphor::logging::log<phosphor::logging::level::ERR>(
2428 "Error to get valid algo");
2429 return ipmi::responseResponseError();
2430 }
2431
2432 if (getCRConfig(ctx, "RotationRankOrder", value))
2433 {
2434 return ipmi::responseResponseError();
2435 }
2436 std::vector<uint8_t>* pResponse =
2437 std::get_if<std::vector<uint8_t>>(&value);
2438 if (!pResponse)
2439 {
2440 phosphor::logging::log<phosphor::logging::level::ERR>(
2441 "Error to get RotationRankOrder property");
2442 return ipmi::responseResponseError();
2443 }
Yong Li83315132019-10-23 17:42:24 +08002444
Cheng C Yang773703a2019-08-15 09:41:11 +08002445 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002446 std::back_inserter(response));
2447
Cheng C Yangf41e3342019-09-10 04:47:23 +08002448 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002449 }
2450 case crParameter::rotationPeriod:
2451 {
2452 if (getCRConfig(ctx, "PeriodOfRotation", value))
2453 {
2454 return ipmi::responseResponseError();
2455 }
2456 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2457 if (!pResponse)
2458 {
2459 phosphor::logging::log<phosphor::logging::level::ERR>(
2460 "Error to get RotationAlgorithm property");
2461 return ipmi::responseResponseError();
2462 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002463 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002464 }
2465 case crParameter::numOfPSU:
2466 {
2467 uint8_t numberOfPSU = getPSUCount();
2468 if (!numberOfPSU)
2469 {
2470 return ipmi::responseResponseError();
2471 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002472 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002473 }
Yong Li19445ab2019-12-20 18:25:29 +08002474 case crParameter::rotationRankOrderEffective:
2475 {
2476 if (getCRConfig(ctx, "RotationRankOrder", value,
2477 "xyz.openbmc_project.PSURedundancy"))
2478 {
2479 return ipmi::responseResponseError();
2480 }
2481 std::vector<uint8_t>* pResponse =
2482 std::get_if<std::vector<uint8_t>>(&value);
2483 if (!pResponse)
2484 {
2485 phosphor::logging::log<phosphor::logging::level::ERR>(
2486 "Error to get effective RotationRankOrder property");
2487 return ipmi::responseResponseError();
2488 }
2489 return ipmi::responseSuccess(parameter, *pResponse);
2490 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002491 default:
2492 {
2493 return ipmi::response(ccParameterNotSupported);
2494 }
2495 }
2496}
2497
Zhu, Yungebe560b02019-04-21 21:19:21 -04002498ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2499 uint8_t faultState,
2500 uint8_t faultGroup,
2501 std::array<uint8_t, 8>& ledStateData)
2502{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002503 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2504 static const std::array<std::string, maxFaultType> faultNames = {
2505 "faultFan", "faultTemp", "faultPower",
2506 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002507
2508 constexpr uint8_t maxFaultSource = 0x4;
2509 constexpr uint8_t skipLEDs = 0xFF;
2510 constexpr uint8_t pinSize = 64;
2511 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002512 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002513
Zhikui Rence4e73f2019-12-06 13:59:47 -08002514 // same pin names need to be defined in dts file
2515 static const std::array<std::array<std::string, groupSize>, groupNum>
2516 faultLedPinNames = {{
2517 "LED_CPU1_CH1_DIMM1_FAULT",
2518 "LED_CPU1_CH1_DIMM2_FAULT",
2519 "LED_CPU1_CH2_DIMM1_FAULT",
2520 "LED_CPU1_CH2_DIMM2_FAULT",
2521 "LED_CPU1_CH3_DIMM1_FAULT",
2522 "LED_CPU1_CH3_DIMM2_FAULT",
2523 "LED_CPU1_CH4_DIMM1_FAULT",
2524 "LED_CPU1_CH4_DIMM2_FAULT",
2525 "LED_CPU1_CH5_DIMM1_FAULT",
2526 "LED_CPU1_CH5_DIMM2_FAULT",
2527 "LED_CPU1_CH6_DIMM1_FAULT",
2528 "LED_CPU1_CH6_DIMM2_FAULT",
2529 "",
2530 "",
2531 "",
2532 "", // end of group1
2533 "LED_CPU2_CH1_DIMM1_FAULT",
2534 "LED_CPU2_CH1_DIMM2_FAULT",
2535 "LED_CPU2_CH2_DIMM1_FAULT",
2536 "LED_CPU2_CH2_DIMM2_FAULT",
2537 "LED_CPU2_CH3_DIMM1_FAULT",
2538 "LED_CPU2_CH3_DIMM2_FAULT",
2539 "LED_CPU2_CH4_DIMM1_FAULT",
2540 "LED_CPU2_CH4_DIMM2_FAULT",
2541 "LED_CPU2_CH5_DIMM1_FAULT",
2542 "LED_CPU2_CH5_DIMM2_FAULT",
2543 "LED_CPU2_CH6_DIMM1_FAULT",
2544 "LED_CPU2_CH6_DIMM2_FAULT",
2545 "",
2546 "",
2547 "",
2548 "", // endof group2
2549 "LED_CPU3_CH1_DIMM1_FAULT",
2550 "LED_CPU3_CH1_DIMM2_FAULT",
2551 "LED_CPU3_CH2_DIMM1_FAULT",
2552 "LED_CPU3_CH2_DIMM2_FAULT",
2553 "LED_CPU3_CH3_DIMM1_FAULT",
2554 "LED_CPU3_CH3_DIMM2_FAULT",
2555 "LED_CPU3_CH4_DIMM1_FAULT",
2556 "LED_CPU3_CH4_DIMM2_FAULT",
2557 "LED_CPU3_CH5_DIMM1_FAULT",
2558 "LED_CPU3_CH5_DIMM2_FAULT",
2559 "LED_CPU3_CH6_DIMM1_FAULT",
2560 "LED_CPU3_CH6_DIMM2_FAULT",
2561 "",
2562 "",
2563 "",
2564 "", // end of group3
2565 "LED_CPU4_CH1_DIMM1_FAULT",
2566 "LED_CPU4_CH1_DIMM2_FAULT",
2567 "LED_CPU4_CH2_DIMM1_FAULT",
2568 "LED_CPU4_CH2_DIMM2_FAULT",
2569 "LED_CPU4_CH3_DIMM1_FAULT",
2570 "LED_CPU4_CH3_DIMM2_FAULT",
2571 "LED_CPU4_CH4_DIMM1_FAULT",
2572 "LED_CPU4_CH4_DIMM2_FAULT",
2573 "LED_CPU4_CH5_DIMM1_FAULT",
2574 "LED_CPU4_CH5_DIMM2_FAULT",
2575 "LED_CPU4_CH6_DIMM1_FAULT",
2576 "LED_CPU4_CH6_DIMM2_FAULT",
2577 "",
2578 "",
2579 "",
2580 "", // end of group4
2581 "LED_FAN1_FAULT",
2582 "LED_FAN2_FAULT",
2583 "LED_FAN3_FAULT",
2584 "LED_FAN4_FAULT",
2585 "LED_FAN5_FAULT",
2586 "LED_FAN6_FAULT",
2587 "LED_FAN7_FAULT",
2588 "LED_FAN8_FAULT",
2589 "",
2590 "",
2591 "",
2592 "",
2593 "",
2594 "",
2595 "",
2596 "" // end of group5
2597 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002598
Zhikui Rence4e73f2019-12-06 13:59:47 -08002599 // Validate the source, fault type --
2600 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2601 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2602 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2603 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2604 // definition differs based on fault type (Byte 2)
2605 // Type Fan=> Group: 0=FanGroupID, FF-not used
2606 // Byte 5-11 00h, not used
2607 // Byte12 FanLedState [7:0]-Fans 7:0
2608 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2609 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2610 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2611 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2612 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2613 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2614 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2615 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002616 if ((sourceId >= maxFaultSource) ||
2617 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2618 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2619 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2620 {
2621 return ipmi::responseParmOutOfRange();
2622 }
2623
Zhikui Rence4e73f2019-12-06 13:59:47 -08002624 size_t pinGroupOffset = 0;
2625 size_t pinGroupMax = pinSize / groupSize;
2626 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002627 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002628 pinGroupOffset = 4;
2629 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002630 }
2631
2632 switch (RemoteFaultType(faultType))
2633 {
2634 case (RemoteFaultType::fan):
2635 case (RemoteFaultType::memory):
2636 {
2637 if (faultGroup == skipLEDs)
2638 {
2639 return ipmi::responseSuccess();
2640 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002641 // calculate led state bit filed count, each byte has 8bits
2642 // the maximum bits will be 8 * 8 bits
2643 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002644
2645 // assemble ledState
2646 uint64_t ledState = 0;
2647 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002648 for (int i = 0; i < sizeof(ledStateData); i++)
2649 {
2650 ledState = (uint64_t)(ledState << 8);
2651 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2652 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002653 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002654
Zhikui Rence4e73f2019-12-06 13:59:47 -08002655 for (int group = 0; group < pinGroupMax; group++)
2656 {
2657 for (int i = 0; i < groupSize; i++)
2658 { // skip non-existing pins
2659 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2660 {
2661 continue;
2662 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002663
Zhikui Rence4e73f2019-12-06 13:59:47 -08002664 gpiod::line line = gpiod::find_line(
2665 faultLedPinNames[group + pinGroupOffset][i]);
2666 if (!line)
2667 {
2668 phosphor::logging::log<phosphor::logging::level::ERR>(
2669 "Not Find Led Gpio Device!",
2670 phosphor::logging::entry(
2671 "DEVICE=%s",
2672 faultLedPinNames[group + pinGroupOffset][i]
2673 .c_str()));
2674 hasError = true;
2675 continue;
2676 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002677
Zhikui Rence4e73f2019-12-06 13:59:47 -08002678 bool activeHigh =
2679 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2680 try
2681 {
2682 line.request(
2683 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2684 activeHigh
2685 ? 0
2686 : gpiod::line_request::FLAG_ACTIVE_LOW});
2687 line.set_value(ledStateBits[i + group * groupSize]);
2688 }
2689 catch (std::system_error&)
2690 {
2691 phosphor::logging::log<phosphor::logging::level::ERR>(
2692 "Error write Led Gpio Device!",
2693 phosphor::logging::entry(
2694 "DEVICE=%s",
2695 faultLedPinNames[group + pinGroupOffset][i]
2696 .c_str()));
2697 hasError = true;
2698 continue;
2699 }
2700 } // for int i
2701 }
2702 if (hasError)
2703 {
2704 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002705 }
2706 break;
2707 }
2708 default:
2709 {
2710 // now only support two fault types
2711 return ipmi::responseParmOutOfRange();
2712 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002713 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002714 return ipmi::responseSuccess();
2715}
2716
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302717ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2718{
2719 uint8_t prodId = 0;
2720 try
2721 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002722 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302723 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002724 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302725 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2726 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002727 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302728 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2729 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302730 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2731 }
2732 catch (std::exception& e)
2733 {
2734 phosphor::logging::log<phosphor::logging::level::ERR>(
2735 "ipmiOEMReadBoardProductId: Product ID read failed!",
2736 phosphor::logging::entry("ERR=%s", e.what()));
2737 }
2738 return ipmi::responseSuccess(prodId);
2739}
2740
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302741/** @brief implements the get security mode command
2742 * @param ctx - ctx pointer
2743 *
2744 * @returns IPMI completion code with following data
2745 * - restriction mode value - As specified in
2746 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2747 * - special mode value - As specified in
2748 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2749 */
2750ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2751{
2752 namespace securityNameSpace =
2753 sdbusplus::xyz::openbmc_project::Control::Security::server;
2754 uint8_t restrictionModeValue = 0;
2755 uint8_t specialModeValue = 0;
2756
2757 boost::system::error_code ec;
2758 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002759 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302760 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2761 restricionModeProperty);
2762 if (ec)
2763 {
2764 phosphor::logging::log<phosphor::logging::level::ERR>(
2765 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2766 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2767 return ipmi::responseUnspecifiedError();
2768 }
2769 restrictionModeValue = static_cast<uint8_t>(
2770 securityNameSpace::RestrictionMode::convertModesFromString(
2771 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302772 auto varSpecialMode =
2773 ctx->bus->yield_method_call<std::variant<std::string>>(
2774 ctx->yield, ec, specialModeService, specialModeBasePath,
2775 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2776 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302777 if (ec)
2778 {
2779 phosphor::logging::log<phosphor::logging::level::ERR>(
2780 "ipmiGetSecurityMode: failed to get SpecialMode property",
2781 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2782 // fall through, let us not worry about SpecialMode property, which is
2783 // not required in user scenario
2784 }
2785 else
2786 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302787 specialModeValue = static_cast<uint8_t>(
2788 securityNameSpace::SpecialMode::convertModesFromString(
2789 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302790 }
2791 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2792}
2793
2794/** @brief implements the set security mode command
2795 * Command allows to upgrade the restriction mode and won't allow
2796 * to downgrade from system interface
2797 * @param ctx - ctx pointer
2798 * @param restrictionMode - restriction mode value to be set.
2799 *
2800 * @returns IPMI completion code
2801 */
2802ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302803 uint8_t restrictionMode,
2804 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302805{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302806#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2807 if (specialMode)
2808 {
2809 return ipmi::responseReqDataLenInvalid();
2810 }
2811#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302812 namespace securityNameSpace =
2813 sdbusplus::xyz::openbmc_project::Control::Security::server;
2814
2815 ChannelInfo chInfo;
2816 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2817 {
2818 phosphor::logging::log<phosphor::logging::level::ERR>(
2819 "ipmiSetSecurityMode: Failed to get Channel Info",
2820 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2821 return ipmi::responseUnspecifiedError();
2822 }
2823 auto reqMode =
2824 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2825
2826 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2827 (reqMode >
2828 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2829 {
2830 return ipmi::responseInvalidFieldRequest();
2831 }
2832
2833 boost::system::error_code ec;
2834 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002835 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302836 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2837 restricionModeProperty);
2838 if (ec)
2839 {
2840 phosphor::logging::log<phosphor::logging::level::ERR>(
2841 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2842 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2843 return ipmi::responseUnspecifiedError();
2844 }
2845 auto currentRestrictionMode =
2846 securityNameSpace::RestrictionMode::convertModesFromString(
2847 std::get<std::string>(varRestrMode));
2848
2849 if (chInfo.mediumType !=
2850 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2851 currentRestrictionMode > reqMode)
2852 {
2853 phosphor::logging::log<phosphor::logging::level::ERR>(
2854 "ipmiSetSecurityMode - Downgrading security mode not supported "
2855 "through system interface",
2856 phosphor::logging::entry(
2857 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2858 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2859 return ipmi::responseCommandNotAvailable();
2860 }
2861
2862 ec.clear();
2863 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002864 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302865 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2866 restricionModeProperty,
2867 static_cast<std::variant<std::string>>(
2868 securityNameSpace::convertForMessage(reqMode)));
2869
2870 if (ec)
2871 {
2872 phosphor::logging::log<phosphor::logging::level::ERR>(
2873 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2874 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2875 return ipmi::responseUnspecifiedError();
2876 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302877
2878#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2879 if (specialMode)
2880 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00002881 constexpr uint8_t mfgMode = 0x01;
2882 // Manufacturing mode is reserved. So can't enable this mode.
2883 if (specialMode.value() == mfgMode)
2884 {
2885 phosphor::logging::log<phosphor::logging::level::INFO>(
2886 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
2887 return ipmi::responseInvalidFieldRequest();
2888 }
2889
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302890 ec.clear();
2891 ctx->bus->yield_method_call<>(
2892 ctx->yield, ec, specialModeService, specialModeBasePath,
2893 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2894 specialModeProperty,
2895 static_cast<std::variant<std::string>>(
2896 securityNameSpace::convertForMessage(
2897 static_cast<securityNameSpace::SpecialMode::Modes>(
2898 specialMode.value()))));
2899
2900 if (ec)
2901 {
2902 phosphor::logging::log<phosphor::logging::level::ERR>(
2903 "ipmiSetSecurityMode: failed to set SpecialMode property",
2904 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2905 return ipmi::responseUnspecifiedError();
2906 }
2907 }
2908#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302909 return ipmi::responseSuccess();
2910}
2911
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002912ipmi::RspType<uint8_t /* restore status */>
2913 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2914{
2915 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2916
2917 if (clr != expClr)
2918 {
2919 return ipmi::responseInvalidFieldRequest();
2920 }
2921 constexpr uint8_t cmdStatus = 0;
2922 constexpr uint8_t cmdDefaultRestore = 0xaa;
2923 constexpr uint8_t cmdFullRestore = 0xbb;
2924 constexpr uint8_t cmdFormat = 0xcc;
2925
2926 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2927
2928 switch (cmd)
2929 {
2930 case cmdStatus:
2931 break;
2932 case cmdDefaultRestore:
2933 case cmdFullRestore:
2934 case cmdFormat:
2935 {
2936 // write file to rwfs root
2937 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2938 std::ofstream restoreFile(restoreOpFname);
2939 if (!restoreFile)
2940 {
2941 return ipmi::responseUnspecifiedError();
2942 }
2943 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05302944
2945 phosphor::logging::log<phosphor::logging::level::WARNING>(
2946 "Restore to default will be performed on next BMC boot",
2947 phosphor::logging::entry("ACTION=0x%0X", cmd));
2948
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002949 break;
2950 }
2951 default:
2952 return ipmi::responseInvalidFieldRequest();
2953 }
2954
2955 constexpr uint8_t restorePending = 0;
2956 constexpr uint8_t restoreComplete = 1;
2957
2958 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2959 ? restorePending
2960 : restoreComplete;
2961 return ipmi::responseSuccess(restoreStatus);
2962}
2963
Chen Yugang39736d52019-07-12 16:24:33 +08002964ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2965{
2966 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002967 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002968
2969 try
2970 {
2971 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2972 std::string service =
2973 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2974 Value variant =
2975 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2976 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2977
2978 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2979 std::get<std::string>(variant)))
2980 {
2981 case nmi::NMISource::BMCSourceSignal::None:
2982 bmcSource = static_cast<uint8_t>(NmiSource::none);
2983 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002984 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2985 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002986 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002987 case nmi::NMISource::BMCSourceSignal::Watchdog:
2988 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002989 break;
2990 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2991 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2992 break;
2993 case nmi::NMISource::BMCSourceSignal::MemoryError:
2994 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2995 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002996 case nmi::NMISource::BMCSourceSignal::PciBusError:
2997 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002998 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002999 case nmi::NMISource::BMCSourceSignal::PCH:
3000 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08003001 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003002 case nmi::NMISource::BMCSourceSignal::Chipset:
3003 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08003004 break;
3005 default:
3006 phosphor::logging::log<phosphor::logging::level::ERR>(
3007 "NMI source: invalid property!",
3008 phosphor::logging::entry(
3009 "PROP=%s", std::get<std::string>(variant).c_str()));
3010 return ipmi::responseResponseError();
3011 }
3012 }
3013 catch (sdbusplus::exception::SdBusError& e)
3014 {
3015 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3016 return ipmi::responseResponseError();
3017 }
3018
3019 return ipmi::responseSuccess(bmcSource);
3020}
3021
3022ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3023{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003024 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003025
3026 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3027 nmi::NMISource::BMCSourceSignal::None;
3028
3029 switch (NmiSource(sourceId))
3030 {
3031 case NmiSource::none:
3032 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3033 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003034 case NmiSource::frontPanelButton:
3035 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003036 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003037 case NmiSource::watchdog:
3038 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003039 break;
3040 case NmiSource::chassisCmd:
3041 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3042 break;
3043 case NmiSource::memoryError:
3044 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3045 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003046 case NmiSource::pciBusError:
3047 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003048 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003049 case NmiSource::pch:
3050 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003051 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003052 case NmiSource::chipset:
3053 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003054 break;
3055 default:
3056 phosphor::logging::log<phosphor::logging::level::ERR>(
3057 "NMI source: invalid property!");
3058 return ipmi::responseResponseError();
3059 }
3060
3061 try
3062 {
3063 // keep NMI signal source
3064 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3065 std::string service =
3066 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003067 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3068 oemNmiBmcSourceObjPathProp,
3069 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003070 // set Enabled property to inform NMI source handling
3071 // to trigger a NMI_OUT BSOD.
3072 // if it's triggered by NMI source property changed,
3073 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3074 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3075 {
3076 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3077 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3078 static_cast<bool>(true));
3079 }
Chen Yugang39736d52019-07-12 16:24:33 +08003080 }
3081 catch (sdbusplus::exception_t& e)
3082 {
3083 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3084 return ipmi::responseResponseError();
3085 }
3086
3087 return ipmi::responseSuccess();
3088}
3089
James Feist63efafa2019-07-24 12:39:21 -07003090namespace dimmOffset
3091{
3092constexpr const char* dimmPower = "DimmPower";
3093constexpr const char* staticCltt = "StaticCltt";
3094constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3095constexpr const char* offsetInterface =
3096 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3097constexpr const char* property = "DimmOffset";
3098
3099}; // namespace dimmOffset
3100
3101ipmi::RspType<>
3102 ipmiOEMSetDimmOffset(uint8_t type,
3103 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3104{
3105 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3106 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3107 {
3108 return ipmi::responseInvalidFieldRequest();
3109 }
3110
3111 if (data.empty())
3112 {
3113 return ipmi::responseInvalidFieldRequest();
3114 }
3115 nlohmann::json json;
3116
3117 std::ifstream jsonStream(dimmOffsetFile);
3118 if (jsonStream.good())
3119 {
3120 json = nlohmann::json::parse(jsonStream, nullptr, false);
3121 if (json.is_discarded())
3122 {
3123 json = nlohmann::json();
3124 }
3125 jsonStream.close();
3126 }
3127
3128 std::string typeName;
3129 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3130 {
3131 typeName = dimmOffset::dimmPower;
3132 }
3133 else
3134 {
3135 typeName = dimmOffset::staticCltt;
3136 }
3137
3138 nlohmann::json& field = json[typeName];
3139
3140 for (const auto& [index, value] : data)
3141 {
3142 field[index] = value;
3143 }
3144
3145 for (nlohmann::json& val : field)
3146 {
3147 if (val == nullptr)
3148 {
3149 val = static_cast<uint8_t>(0);
3150 }
3151 }
3152
3153 std::ofstream output(dimmOffsetFile);
3154 if (!output.good())
3155 {
3156 std::cerr << "Error writing json file\n";
3157 return ipmi::responseResponseError();
3158 }
3159
3160 output << json.dump(4);
3161
3162 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3163 {
3164 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3165
3166 std::variant<std::vector<uint8_t>> offsets =
3167 field.get<std::vector<uint8_t>>();
3168 auto call = bus->new_method_call(
3169 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3170 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3171 try
3172 {
3173 bus->call(call);
3174 }
3175 catch (sdbusplus::exception_t& e)
3176 {
3177 phosphor::logging::log<phosphor::logging::level::ERR>(
3178 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3179 phosphor::logging::entry("ERR=%s", e.what()));
3180 return ipmi::responseResponseError();
3181 }
3182 }
3183
3184 return ipmi::responseSuccess();
3185}
3186
3187ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3188{
3189
3190 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3191 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3192 {
3193 return ipmi::responseInvalidFieldRequest();
3194 }
3195
3196 std::ifstream jsonStream(dimmOffsetFile);
3197
3198 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3199 if (json.is_discarded())
3200 {
3201 std::cerr << "File error in " << dimmOffsetFile << "\n";
3202 return ipmi::responseResponseError();
3203 }
3204
3205 std::string typeName;
3206 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3207 {
3208 typeName = dimmOffset::dimmPower;
3209 }
3210 else
3211 {
3212 typeName = dimmOffset::staticCltt;
3213 }
3214
3215 auto it = json.find(typeName);
3216 if (it == json.end())
3217 {
3218 return ipmi::responseInvalidFieldRequest();
3219 }
3220
3221 if (it->size() <= index)
3222 {
3223 return ipmi::responseInvalidFieldRequest();
3224 }
3225
3226 uint8_t resp = it->at(index).get<uint8_t>();
3227 return ipmi::responseSuccess(resp);
3228}
3229
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003230namespace boot_options
3231{
3232
3233using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3234using IpmiValue = uint8_t;
3235constexpr auto ipmiDefault = 0;
3236
3237std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3238 {0x01, Source::Sources::Network},
3239 {0x02, Source::Sources::Disk},
3240 {0x05, Source::Sources::ExternalMedia},
3241 {0x0f, Source::Sources::RemovableMedia},
3242 {ipmiDefault, Source::Sources::Default}};
3243
3244std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003245 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003246
3247std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3248 {Source::Sources::Network, 0x01},
3249 {Source::Sources::Disk, 0x02},
3250 {Source::Sources::ExternalMedia, 0x05},
3251 {Source::Sources::RemovableMedia, 0x0f},
3252 {Source::Sources::Default, ipmiDefault}};
3253
3254std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003255 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003256
3257static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3258static constexpr auto bootSourceIntf =
3259 "xyz.openbmc_project.Control.Boot.Source";
3260static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3261static constexpr auto persistentObjPath =
3262 "/xyz/openbmc_project/control/host0/boot";
3263static constexpr auto oneTimePath =
3264 "/xyz/openbmc_project/control/host0/boot/one_time";
3265static constexpr auto bootSourceProp = "BootSource";
3266static constexpr auto bootModeProp = "BootMode";
3267static constexpr auto oneTimeBootEnableProp = "Enabled";
3268static constexpr auto httpBootMode =
3269 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3270
3271enum class BootOptionParameter : size_t
3272{
3273 setInProgress = 0x0,
3274 bootFlags = 0x5,
3275};
3276static constexpr uint8_t setComplete = 0x0;
3277static constexpr uint8_t setInProgress = 0x1;
3278static uint8_t transferStatus = setComplete;
3279static constexpr uint8_t setParmVersion = 0x01;
3280static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3281static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3282static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3283static constexpr uint8_t httpBoot = 0xd;
3284static constexpr uint8_t bootSourceMask = 0x3c;
3285
3286} // namespace boot_options
3287
3288ipmi::RspType<uint8_t, // version
3289 uint8_t, // param
3290 uint8_t, // data0, dependent on parameter
3291 std::optional<uint8_t> // data1, dependent on parameter
3292 >
3293 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3294{
3295 using namespace boot_options;
3296 uint8_t bootOption = 0;
3297
3298 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3299 {
3300 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3301 std::nullopt);
3302 }
3303
3304 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3305 {
3306 phosphor::logging::log<phosphor::logging::level::ERR>(
3307 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003308 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003309 }
3310
3311 try
3312 {
3313 auto oneTimeEnabled = false;
3314 // read one time Enabled property
3315 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3316 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3317 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3318 enabledIntf, oneTimeBootEnableProp);
3319 oneTimeEnabled = std::get<bool>(variant);
3320
3321 // get BootSource and BootMode properties
3322 // according to oneTimeEnable
3323 auto bootObjPath = oneTimePath;
3324 if (oneTimeEnabled == false)
3325 {
3326 bootObjPath = persistentObjPath;
3327 }
3328
3329 service = getService(*dbus, bootModeIntf, bootObjPath);
3330 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3331 bootModeProp);
3332
3333 auto bootMode =
3334 Mode::convertModesFromString(std::get<std::string>(variant));
3335
3336 service = getService(*dbus, bootSourceIntf, bootObjPath);
3337 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3338 bootSourceProp);
3339
3340 if (std::get<std::string>(variant) == httpBootMode)
3341 {
3342 bootOption = httpBoot;
3343 }
3344 else
3345 {
3346 auto bootSource = Source::convertSourcesFromString(
3347 std::get<std::string>(variant));
3348 bootOption = sourceDbusToIpmi.at(bootSource);
3349 if (Source::Sources::Default == bootSource)
3350 {
3351 bootOption = modeDbusToIpmi.at(bootMode);
3352 }
3353 }
3354
3355 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3356 : setParmBootFlagsValidPermanent;
3357 bootOption <<= 2; // shift for responseconstexpr
3358 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3359 bootOption);
3360 }
3361 catch (sdbusplus::exception_t& e)
3362 {
3363 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3364 return ipmi::responseResponseError();
3365 }
3366}
3367
3368ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3369 std::optional<uint8_t> bootOption)
3370{
3371 using namespace boot_options;
3372 auto oneTimeEnabled = false;
3373
3374 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3375 {
3376 if (bootOption)
3377 {
3378 return ipmi::responseReqDataLenInvalid();
3379 }
3380
3381 if (transferStatus == setInProgress)
3382 {
3383 phosphor::logging::log<phosphor::logging::level::ERR>(
3384 "boot option set in progress!");
3385 return ipmi::responseResponseError();
3386 }
3387
3388 transferStatus = bootParam;
3389 return ipmi::responseSuccess();
3390 }
3391
3392 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3393 {
3394 phosphor::logging::log<phosphor::logging::level::ERR>(
3395 "Unsupported parameter");
Jayaprakash Mutyala3694d072021-07-22 10:34:37 +00003396 return ipmi::response(ccParameterNotSupported);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003397 }
3398
3399 if (!bootOption)
3400 {
3401 return ipmi::responseReqDataLenInvalid();
3402 }
3403
3404 if (((bootOption.value() & bootSourceMask) >> 2) !=
3405 httpBoot) // not http boot, exit
3406 {
3407 phosphor::logging::log<phosphor::logging::level::ERR>(
3408 "wrong boot option parameter!");
3409 return ipmi::responseParmOutOfRange();
3410 }
3411
3412 try
3413 {
3414 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3415 setParmBootFlagsPermanent;
3416
3417 // read one time Enabled property
3418 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3419 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3420 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3421 enabledIntf, oneTimeBootEnableProp);
3422 oneTimeEnabled = std::get<bool>(variant);
3423
3424 /*
3425 * Check if the current boot setting is onetime or permanent, if the
3426 * request in the command is otherwise, then set the "Enabled"
3427 * property in one_time object path to 'True' to indicate onetime
3428 * and 'False' to indicate permanent.
3429 *
3430 * Once the onetime/permanent setting is applied, then the bootMode
3431 * and bootSource is updated for the corresponding object.
3432 */
3433 if (permanent == oneTimeEnabled)
3434 {
3435 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3436 oneTimeBootEnableProp, !permanent);
3437 }
3438
3439 // set BootSource and BootMode properties
3440 // according to oneTimeEnable or persistent
3441 auto bootObjPath = oneTimePath;
3442 if (oneTimeEnabled == false)
3443 {
3444 bootObjPath = persistentObjPath;
3445 }
3446 std::string bootMode =
3447 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3448 std::string bootSource = httpBootMode;
3449
3450 service = getService(*dbus, bootModeIntf, bootObjPath);
3451 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3452 bootMode);
3453
3454 service = getService(*dbus, bootSourceIntf, bootObjPath);
3455 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3456 bootSourceProp, bootSource);
3457 }
3458 catch (sdbusplus::exception_t& e)
3459 {
3460 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3461 return ipmi::responseResponseError();
3462 }
3463
3464 return ipmi::responseSuccess();
3465}
3466
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003467using BasicVariantType =
3468 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3469 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3470 uint16_t, uint8_t, bool>;
3471using PropertyMapType =
3472 boost::container::flat_map<std::string, BasicVariantType>;
3473static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3474 "xyz.openbmc_project.Configuration.PSUPresence"};
3475int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3476 std::vector<uint64_t>& addrTable)
3477{
3478 boost::system::error_code ec;
3479 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3480 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3481 "/xyz/openbmc_project/object_mapper",
3482 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3483 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3484 if (ec)
3485 {
3486 phosphor::logging::log<phosphor::logging::level::ERR>(
3487 "Failed to set dbus property to cold redundancy");
3488 return -1;
3489 }
3490 for (const auto& object : subtree)
3491 {
3492 std::string pathName = object.first;
3493 for (const auto& serviceIface : object.second)
3494 {
3495 std::string serviceName = serviceIface.first;
3496
3497 ec.clear();
3498 PropertyMapType propMap =
3499 ctx->bus->yield_method_call<PropertyMapType>(
3500 ctx->yield, ec, serviceName, pathName,
3501 "org.freedesktop.DBus.Properties", "GetAll",
3502 "xyz.openbmc_project.Configuration.PSUPresence");
3503 if (ec)
3504 {
3505 phosphor::logging::log<phosphor::logging::level::ERR>(
3506 "Failed to set dbus property to cold redundancy");
3507 return -1;
3508 }
3509 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3510 auto psuAddress =
3511 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3512
3513 if (psuBus == nullptr || psuAddress == nullptr)
3514 {
3515 std::cerr << "error finding necessary "
3516 "entry in configuration\n";
3517 return -1;
3518 }
3519 bus = static_cast<uint8_t>(*psuBus);
3520 addrTable = *psuAddress;
3521 return 0;
3522 }
3523 }
3524 return -1;
3525}
3526
3527static const constexpr uint8_t addrOffset = 8;
3528static const constexpr uint8_t psuRevision = 0xd9;
3529static const constexpr uint8_t defaultPSUBus = 7;
3530// Second Minor, Primary Minor, Major
3531static const constexpr size_t verLen = 3;
3532ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3533{
3534 uint8_t bus = defaultPSUBus;
3535 std::vector<uint64_t> addrTable;
3536 std::vector<uint8_t> result;
3537 if (getPSUAddress(ctx, bus, addrTable))
3538 {
3539 std::cerr << "Failed to get PSU bus and address\n";
3540 return ipmi::responseResponseError();
3541 }
3542
3543 for (const auto& slaveAddr : addrTable)
3544 {
3545 std::vector<uint8_t> writeData = {psuRevision};
3546 std::vector<uint8_t> readBuf(verLen);
3547 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3548 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3549
3550 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3551 if (retI2C != ipmi::ccSuccess)
3552 {
3553 for (size_t idx = 0; idx < verLen; idx++)
3554 {
3555 result.emplace_back(0x00);
3556 }
3557 }
3558 else
3559 {
3560 for (const uint8_t& data : readBuf)
3561 {
3562 result.emplace_back(data);
3563 }
3564 }
3565 }
3566
3567 return ipmi::responseSuccess(result);
3568}
3569
srikanta mondal2030d7c2020-05-03 17:25:25 +00003570std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3571 const std::string& name)
3572{
3573 Value dbusValue = 0;
3574 std::string serviceName;
3575
3576 boost::system::error_code ec =
3577 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3578
3579 if (ec)
3580 {
3581 phosphor::logging::log<phosphor::logging::level::ERR>(
3582 "Failed to perform Multinode getService.");
3583 return std::nullopt;
3584 }
3585
3586 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3587 multiNodeIntf, name, dbusValue);
3588 if (ec)
3589 {
3590 phosphor::logging::log<phosphor::logging::level::ERR>(
3591 "Failed to perform Multinode get property");
3592 return std::nullopt;
3593 }
3594
3595 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3596 if (!multiNodeVal)
3597 {
3598 phosphor::logging::log<phosphor::logging::level::ERR>(
3599 "getMultiNodeInfoPresence: error to get multinode");
3600 return std::nullopt;
3601 }
3602 return *multiNodeVal;
3603}
3604
3605/** @brief implements OEM get reading command
3606 * @param domain ID
3607 * @param reading Type
3608 * - 00h = platform Power Consumption
3609 * - 01h = inlet Air Temp
3610 * - 02h = icc_TDC from PECI
3611 * @param reserved, write as 0000h
3612 *
3613 * @returns IPMI completion code plus response data
3614 * - response
3615 * - domain ID
3616 * - reading Type
3617 * - 00h = platform Power Consumption
3618 * - 01h = inlet Air Temp
3619 * - 02h = icc_TDC from PECI
3620 * - reading
3621 */
3622ipmi::RspType<uint4_t, // domain ID
3623 uint4_t, // reading Type
3624 uint16_t // reading Value
3625 >
3626 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3627 uint4_t readingType, uint16_t reserved)
3628{
3629 constexpr uint8_t platformPower = 0;
3630 constexpr uint8_t inletAirTemp = 1;
3631 constexpr uint8_t iccTdc = 2;
3632
3633 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3634 {
3635 return ipmi::responseInvalidFieldRequest();
3636 }
3637
3638 // This command should run only from multi-node product.
3639 // For all other platforms this command will return invalid.
3640
3641 std::optional<uint8_t> nodeInfo =
3642 getMultiNodeInfoPresence(ctx, "NodePresence");
3643 if (!nodeInfo || !*nodeInfo)
3644 {
3645 return ipmi::responseInvalidCommand();
3646 }
3647
3648 uint16_t oemReadingValue = 0;
3649 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3650 {
3651 double value = 0;
3652 boost::system::error_code ec = ipmi::getDbusProperty(
3653 ctx, "xyz.openbmc_project.HwmonTempSensor",
3654 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3655 "xyz.openbmc_project.Sensor.Value", "Value", value);
3656 if (ec)
3657 {
3658 phosphor::logging::log<phosphor::logging::level::ERR>(
3659 "Failed to get BMC Get OEM temperature",
3660 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3661 return ipmi::responseUnspecifiedError();
3662 }
3663 // Take the Inlet temperature
3664 oemReadingValue = static_cast<uint16_t>(value);
3665 }
3666 else
3667 {
3668 phosphor::logging::log<phosphor::logging::level::ERR>(
3669 "Currently Get OEM Reading support only for Inlet Air Temp");
3670 return ipmi::responseParmOutOfRange();
3671 }
3672 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3673}
3674
AppaRao Puli28972062019-11-11 02:04:45 +05303675/** @brief implements the maximum size of
3676 * bridgeable messages used between KCS and
3677 * IPMB interfacesget security mode command.
3678 *
3679 * @returns IPMI completion code with following data
3680 * - KCS Buffer Size (In multiples of four bytes)
3681 * - IPMB Buffer Size (In multiples of four bytes)
3682 **/
3683ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3684{
3685 // for now this is hard coded; really this number is dependent on
3686 // the BMC kcs driver as well as the host kcs driver....
3687 // we can't know the latter.
3688 uint8_t kcsMaxBufferSize = 63 / 4;
3689 uint8_t ipmbMaxBufferSize = 128 / 4;
3690
3691 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3692}
3693
Jason M. Bills64796042018-10-03 16:51:55 -07003694static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003695{
3696 phosphor::logging::log<phosphor::logging::level::INFO>(
3697 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003698 ipmiPrintAndRegister(intel::netFnGeneral,
3699 intel::general::cmdGetChassisIdentifier, NULL,
3700 ipmiOEMGetChassisIdentifier,
3701 PRIVILEGE_USER); // get chassis identifier
3702
3703 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3704 NULL, ipmiOEMSetSystemGUID,
3705 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003706
3707 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003708 registerHandler(prioOemBase, intel::netFnGeneral,
3709 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3710 ipmiOEMDisableBMCSystemReset);
3711
Jason M. Billsb02bf092019-08-15 13:01:56 -07003712 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003713 registerHandler(prioOemBase, intel::netFnGeneral,
3714 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3715 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003716
Vernon Mauery98bbf692019-09-16 11:14:59 -07003717 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3718 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003719
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003720 registerHandler(prioOemBase, intel::netFnGeneral,
3721 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3722 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003723
Vernon Mauery98bbf692019-09-16 11:14:59 -07003724 ipmiPrintAndRegister(intel::netFnGeneral,
3725 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3726 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303727
Vernon Mauery98bbf692019-09-16 11:14:59 -07003728 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3729 intel::general::cmdSendEmbeddedFWUpdStatus,
3730 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303731
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303732 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3733 Privilege::Admin, ipmiOEMSlotIpmb);
3734
Vernon Mauery98bbf692019-09-16 11:14:59 -07003735 ipmiPrintAndRegister(intel::netFnGeneral,
3736 intel::general::cmdSetPowerRestoreDelay, NULL,
3737 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3738
3739 ipmiPrintAndRegister(intel::netFnGeneral,
3740 intel::general::cmdGetPowerRestoreDelay, NULL,
3741 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3742
3743 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3744 intel::general::cmdSetOEMUser2Activation,
3745 Privilege::Callback, ipmiOEMSetUser2Activation);
3746
3747 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3748 intel::general::cmdSetSpecialUserPassword,
3749 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303750
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003751 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003752 registerHandler(prioOemBase, intel::netFnGeneral,
3753 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3754 ipmiOEMGetProcessorErrConfig);
3755
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003756 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003757 registerHandler(prioOemBase, intel::netFnGeneral,
3758 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3759 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003760
Vernon Mauery98bbf692019-09-16 11:14:59 -07003761 ipmiPrintAndRegister(intel::netFnGeneral,
3762 intel::general::cmdSetShutdownPolicy, NULL,
3763 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003764
Vernon Mauery98bbf692019-09-16 11:14:59 -07003765 ipmiPrintAndRegister(intel::netFnGeneral,
3766 intel::general::cmdGetShutdownPolicy, NULL,
3767 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003768
anil kumar appanaf945eee2019-09-25 23:29:11 +00003769 registerHandler(prioOemBase, intel::netFnGeneral,
3770 intel::general::cmdSetFanConfig, Privilege::User,
3771 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003772
Vernon Mauery98bbf692019-09-16 11:14:59 -07003773 registerHandler(prioOemBase, intel::netFnGeneral,
3774 intel::general::cmdGetFanConfig, Privilege::User,
3775 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003776
Vernon Mauery98bbf692019-09-16 11:14:59 -07003777 registerHandler(prioOemBase, intel::netFnGeneral,
3778 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3779 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003780
Vernon Mauery98bbf692019-09-16 11:14:59 -07003781 registerHandler(prioOemBase, intel::netFnGeneral,
3782 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3783 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003784
Vernon Mauery98bbf692019-09-16 11:14:59 -07003785 registerHandler(prioOemBase, intel::netFnGeneral,
3786 intel::general::cmdSetFscParameter, Privilege::User,
3787 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003788
Vernon Mauery98bbf692019-09-16 11:14:59 -07003789 registerHandler(prioOemBase, intel::netFnGeneral,
3790 intel::general::cmdGetFscParameter, Privilege::User,
3791 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303792
Vernon Mauery98bbf692019-09-16 11:14:59 -07003793 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3794 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3795 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003796
Vernon Mauery98bbf692019-09-16 11:14:59 -07003797 registerHandler(prioOemBase, intel::netFnGeneral,
3798 intel::general::cmdGetNmiStatus, Privilege::User,
3799 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003800
Vernon Mauery98bbf692019-09-16 11:14:59 -07003801 registerHandler(prioOemBase, intel::netFnGeneral,
3802 intel::general::cmdSetNmiStatus, Privilege::Operator,
3803 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003804
Vernon Mauery98bbf692019-09-16 11:14:59 -07003805 registerHandler(prioOemBase, intel::netFnGeneral,
3806 intel::general::cmdGetEfiBootOptions, Privilege::User,
3807 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003808
Vernon Mauery98bbf692019-09-16 11:14:59 -07003809 registerHandler(prioOemBase, intel::netFnGeneral,
3810 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3811 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303812
Vernon Mauery98bbf692019-09-16 11:14:59 -07003813 registerHandler(prioOemBase, intel::netFnGeneral,
3814 intel::general::cmdGetSecurityMode, Privilege::User,
3815 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303816
Vernon Mauery98bbf692019-09-16 11:14:59 -07003817 registerHandler(prioOemBase, intel::netFnGeneral,
3818 intel::general::cmdSetSecurityMode, Privilege::Admin,
3819 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003820
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003821 registerHandler(prioOemBase, intel::netFnGeneral,
3822 intel::general::cmdGetLEDStatus, Privilege::Admin,
3823 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003824
Vernon Mauery98bbf692019-09-16 11:14:59 -07003825 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3826 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3827 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3828
3829 registerHandler(prioOemBase, intel::netFnGeneral,
3830 intel::general::cmdSetFaultIndication, Privilege::Operator,
3831 ipmiOEMSetFaultIndication);
3832
3833 registerHandler(prioOemBase, intel::netFnGeneral,
3834 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3835 ipmiOEMSetCRConfig);
3836
3837 registerHandler(prioOemBase, intel::netFnGeneral,
3838 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3839 ipmiOEMGetCRConfig);
3840
3841 registerHandler(prioOemBase, intel::netFnGeneral,
3842 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003843 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003844
Vernon Mauery98bbf692019-09-16 11:14:59 -07003845 registerHandler(prioOemBase, intel::netFnGeneral,
3846 intel::general::cmdSetDimmOffset, Privilege::Operator,
3847 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003848
Vernon Mauery98bbf692019-09-16 11:14:59 -07003849 registerHandler(prioOemBase, intel::netFnGeneral,
3850 intel::general::cmdGetDimmOffset, Privilege::Operator,
3851 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003852
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003853 registerHandler(prioOemBase, intel::netFnGeneral,
3854 intel::general::cmdGetPSUVersion, Privilege::User,
3855 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303856
3857 registerHandler(prioOemBase, intel::netFnGeneral,
3858 intel::general::cmdGetBufferSize, Privilege::User,
3859 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00003860
3861 registerHandler(prioOemBase, intel::netFnGeneral,
3862 intel::general::cmdOEMGetReading, Privilege::User,
3863 ipmiOEMGetReading);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003864}
3865
3866} // namespace ipmi