blob: f5328844b5b95e30ad938ab69dec0d49dad9c6ab [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
Jia, Chunhuicc49b542019-03-20 15:41:07 +080021#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080022
Chen Yugang7a04f3a2019-10-08 11:12:35 +080023#include <appcommands.hpp>
James Feist91244a62019-02-19 15:04:54 -080024#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080025#include <boost/process/child.hpp>
26#include <boost/process/io.hpp>
Yong Li0669d192019-05-06 14:01:46 +080027#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070028#include <commandutils.hpp>
Zhikui Rence4e73f2019-12-06 13:59:47 -080029#include <gpiod.hpp>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080030#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070031#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070032#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080033#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <phosphor-logging/log.hpp>
35#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053036#include <sdbusplus/message/types.hpp>
Chen Yugang97cf96e2019-11-01 08:55:11 +080037#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080038#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
39#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080040#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053041#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053042#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080043
James Feistfcd2d3a2020-05-28 10:38:15 -070044#include <array>
45#include <filesystem>
46#include <iostream>
47#include <regex>
48#include <string>
49#include <variant>
50#include <vector>
51
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080052namespace ipmi
53{
Jason M. Bills64796042018-10-03 16:51:55 -070054static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070055
Jason M. Bills64796042018-10-03 16:51:55 -070056static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080057
Suryakanth Sekard509eb92018-11-15 17:44:11 +053058static constexpr auto ethernetIntf =
59 "xyz.openbmc_project.Network.EthernetInterface";
60static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
61static constexpr auto networkService = "xyz.openbmc_project.Network";
62static constexpr auto networkRoot = "/xyz/openbmc_project/network";
63
Chen Yugang97cf96e2019-11-01 08:55:11 +080064static constexpr const char* oemNmiSourceIntf =
65 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080066static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080067 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080068static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
69static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
70
James Feist63efafa2019-07-24 12:39:21 -070071static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
72
Chen Yugang39736d52019-07-12 16:24:33 +080073enum class NmiSource : uint8_t
74{
75 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080076 frontPanelButton = 1,
77 watchdog = 2,
78 chassisCmd = 3,
79 memoryError = 4,
80 pciBusError = 5,
81 pch = 6,
82 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080083};
84
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053085enum class SpecialUserIndex : uint8_t
86{
87 rootUser = 0,
88 atScaleDebugUser = 1
89};
90
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053091static constexpr const char* restricionModeService =
92 "xyz.openbmc_project.RestrictionMode.Manager";
93static constexpr const char* restricionModeBasePath =
94 "/xyz/openbmc_project/control/security/restriction_mode";
95static constexpr const char* restricionModeIntf =
96 "xyz.openbmc_project.Control.Security.RestrictionMode";
97static constexpr const char* restricionModeProperty = "RestrictionMode";
98
99static constexpr const char* specialModeService =
100 "xyz.openbmc_project.SpecialMode";
101static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530102 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530103static constexpr const char* specialModeIntf =
104 "xyz.openbmc_project.Security.SpecialMode";
105static constexpr const char* specialModeProperty = "SpecialMode";
106
107static constexpr const char* dBusPropertyIntf =
108 "org.freedesktop.DBus.Properties";
109static constexpr const char* dBusPropertyGetMethod = "Get";
110static constexpr const char* dBusPropertySetMethod = "Set";
111
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800112// return code: 0 successful
113int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
114{
115 std::string objpath = "/xyz/openbmc_project/FruDevice";
116 std::string intf = "xyz.openbmc_project.FruDeviceManager";
117 std::string service = getService(bus, intf, objpath);
118 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
119 if (valueTree.empty())
120 {
121 phosphor::logging::log<phosphor::logging::level::ERR>(
122 "No object implements interface",
123 phosphor::logging::entry("INTF=%s", intf.c_str()));
124 return -1;
125 }
126
Jason M. Bills64796042018-10-03 16:51:55 -0700127 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800128 {
129 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
130 if (interface == item.second.end())
131 {
132 continue;
133 }
134
135 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
136 if (property == interface->second.end())
137 {
138 continue;
139 }
140
141 try
142 {
143 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700144 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700145 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800146 {
147 phosphor::logging::log<phosphor::logging::level::ERR>(
148 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800149 return -1;
150 }
Jason M. Bills64796042018-10-03 16:51:55 -0700151 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800152 return 0;
153 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700154 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800155 {
Jason M. Bills64796042018-10-03 16:51:55 -0700156 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800157 return -1;
158 }
159 }
160 return -1;
161}
Jason M. Bills64796042018-10-03 16:51:55 -0700162
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800163// Returns the Chassis Identifier (serial #)
164ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
165 ipmi_request_t request,
166 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700167 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800168 ipmi_context_t context)
169{
170 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700171 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800172 {
Jason M. Bills64796042018-10-03 16:51:55 -0700173 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800174 return IPMI_CC_REQ_DATA_LEN_INVALID;
175 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700176 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
177 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800178 {
Jason M. Bills64796042018-10-03 16:51:55 -0700179 *dataLen = serial.size(); // length will never exceed response length
180 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800181 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700182 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 return IPMI_CC_OK;
184 }
Jason M. Bills64796042018-10-03 16:51:55 -0700185 *dataLen = 0;
186 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800187}
188
189ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
190 ipmi_request_t request,
191 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700192 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800193{
194 static constexpr size_t safeBufferLength = 50;
195 char buf[safeBufferLength] = {0};
196 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
197
Jason M. Bills64796042018-10-03 16:51:55 -0700198 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800199 {
Jason M. Bills64796042018-10-03 16:51:55 -0700200 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800201 return IPMI_CC_REQ_DATA_LEN_INVALID;
202 }
203
Jason M. Bills64796042018-10-03 16:51:55 -0700204 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800205
206 snprintf(
207 buf, safeBufferLength,
208 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
209 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
210 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
211 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
212 Data->node3, Data->node2, Data->node1);
213 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
214 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800215
216 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
217 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700218 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
219 std::string service = getService(*dbus, intf, objpath);
220 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800221 return IPMI_CC_OK;
222}
223
Jason M. Billsb02bf092019-08-15 13:01:56 -0700224ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
225 uint7_t reserved1)
226{
227 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
228
229 try
230 {
231 auto service =
232 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
233 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
234 bmcResetDisablesIntf, "ResetOnSMI",
235 !disableResetOnSMI);
236 }
237 catch (std::exception& e)
238 {
239 phosphor::logging::log<phosphor::logging::level::ERR>(
240 "Failed to set BMC reset disables",
241 phosphor::logging::entry("EXCEPTION=%s", e.what()));
242 return ipmi::responseUnspecifiedError();
243 }
244
245 return ipmi::responseSuccess();
246}
247
248ipmi::RspType<bool, // disableResetOnSMI
249 uint7_t // reserved
250 >
251 ipmiOEMGetBMCResetDisables()
252{
253 bool disableResetOnSMI = true;
254
255 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
256 try
257 {
258 auto service =
259 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
260 Value variant =
261 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
262 bmcResetDisablesIntf, "ResetOnSMI");
263 disableResetOnSMI = !std::get<bool>(variant);
264 }
265 catch (std::exception& e)
266 {
267 phosphor::logging::log<phosphor::logging::level::ERR>(
268 "Failed to get BMC reset disables",
269 phosphor::logging::entry("EXCEPTION=%s", e.what()));
270 return ipmi::responseUnspecifiedError();
271 }
272
273 return ipmi::responseSuccess(disableResetOnSMI, 0);
274}
275
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800276ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
277 ipmi_request_t request, ipmi_response_t response,
278 ipmi_data_len_t dataLen, ipmi_context_t context)
279{
280 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
281
Jason M. Bills64796042018-10-03 16:51:55 -0700282 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800283 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800284 *dataLen = 0;
285 return IPMI_CC_REQ_DATA_LEN_INVALID;
286 }
Jason M. Bills64796042018-10-03 16:51:55 -0700287 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800288
Vernon Mauery15419dd2019-05-24 09:40:30 -0700289 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000290 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
291 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800292 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
294 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700295 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800296 *dataLen = 1;
297 return IPMI_CC_OK;
298}
299
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530300bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
301 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800302{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800303 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530304 std::string bmcVersion;
305 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800306 {
307 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800308 }
309
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530310 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800311 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800312 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800313 MetaRevision revision = rev.value();
314 bmcMajor = revision.major;
315
316 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
317 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
318 }
319
320 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530321 std::string meVersion;
322 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800323 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800324 return false;
325 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530326 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
327 constexpr size_t matchedPhosphor = 6;
328 std::smatch results;
329 if (std::regex_match(meVersion, results, pattern1))
330 {
331 if (results.size() == matchedPhosphor)
332 {
333 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
334 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
335 }
336 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800337 return true;
338}
339
340ipmi::RspType<
341 std::variant<std::string,
342 std::tuple<uint8_t, std::array<uint8_t, 2>,
343 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
344 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
345 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530346 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
347 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530348 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800349{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800350 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
351 {
352 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800353 }
354
355 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800356 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800357 {
358 case OEMDevEntityType::biosId:
359 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530360 // Byte 2&3, Only used with selecting BIOS
361 if (!countToRead || !offset)
362 {
363 return ipmi::responseReqDataLenInvalid();
364 }
365
Vernon Mauery15419dd2019-05-24 09:40:30 -0700366 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800367 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000368 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800369 try
370 {
Yong Li2742b852019-12-16 14:55:11 +0800371 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000372 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800373 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700374 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530375 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800376 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800377 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800378 }
Jason M. Bills64796042018-10-03 16:51:55 -0700379 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530380 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700381 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530382 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700383 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800384 else
385 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530386 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800387 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800388
389 std::string readBuf = {0};
390 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530391 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800392 (readBuf.begin()));
393 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800394 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700395 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800396 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800397 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800398 }
399 }
400 break;
401
402 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800403 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530404 // Byte 2&3, Only used with selecting BIOS
405 if (countToRead || offset)
406 {
407 return ipmi::responseReqDataLenInvalid();
408 }
409
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800410 constexpr const size_t verLen = 2;
411 constexpr const size_t verTotalLen = 10;
412 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
413 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
414 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
415 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
416 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
417 // data0/1: BMC version number; data6/7: ME version number
418 // the others: HSC0/1/2 version number, not avaible.
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530419 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800420 {
421 return ipmi::responseUnspecifiedError();
422 }
423 return ipmi::responseSuccess(
424 std::tuple<
425 uint8_t, std::array<uint8_t, verLen>,
426 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
427 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
428 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
429 }
430 break;
431
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800432 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800433 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530434 // Byte 2&3, Only used with selecting BIOS
435 if (countToRead || offset)
436 {
437 return ipmi::responseReqDataLenInvalid();
438 }
439
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800440 constexpr const size_t sdrLen = 2;
441 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
442 return ipmi::responseSuccess(
443 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
444 readBuf});
445 }
446 break;
447
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800448 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800449 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800450 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800451}
452
453ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
454 ipmi_request_t request, ipmi_response_t response,
455 ipmi_data_len_t dataLen, ipmi_context_t context)
456{
457 if (*dataLen != 0)
458 {
Jason M. Bills64796042018-10-03 16:51:55 -0700459 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800460 return IPMI_CC_REQ_DATA_LEN_INVALID;
461 }
462
463 *dataLen = 1;
464 uint8_t* res = reinterpret_cast<uint8_t*>(response);
465 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
466 // AIC is available so that BIOS will not timeout repeatly which leads to
467 // slow booting.
468 *res = 0; // Byte1=Count of SlotPosition/FruID records.
469 return IPMI_CC_OK;
470}
471
Jason M. Bills64796042018-10-03 16:51:55 -0700472ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
473 ipmi_request_t request,
474 ipmi_response_t response,
475 ipmi_data_len_t dataLen,
476 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800477{
Jason M. Bills64796042018-10-03 16:51:55 -0700478 GetPowerRestoreDelayRes* resp =
479 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
480
481 if (*dataLen != 0)
482 {
483 *dataLen = 0;
484 return IPMI_CC_REQ_DATA_LEN_INVALID;
485 }
486
Vernon Mauery15419dd2019-05-24 09:40:30 -0700487 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700488 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700489 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700490 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700491 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700492 powerRestoreDelayIntf, powerRestoreDelayProp);
493
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700494 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700495 resp->byteLSB = delay;
496 resp->byteMSB = delay >> 8;
497
498 *dataLen = sizeof(GetPowerRestoreDelayRes);
499
500 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800501}
502
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800503static uint8_t bcdToDec(uint8_t val)
504{
505 return ((val / 16 * 10) + (val % 16));
506}
507
508// Allows an update utility or system BIOS to send the status of an embedded
509// firmware update attempt to the BMC. After received, BMC will create a logging
510// record.
511ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
512 uint8_t majorRevision,
513 uint8_t minorRevision,
514 uint32_t auxInfo)
515{
516 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700517 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800518 target = (target & selEvtTargetMask) >> selEvtTargetShift;
519
520 /* make sure the status is 0, 1, or 2 as per the spec */
521 if (status > 2)
522 {
523 return ipmi::response(ipmi::ccInvalidFieldRequest);
524 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700525 /* make sure the target is 0, 1, 2, or 4 as per the spec */
526 if (target > 4 || target == 3)
527 {
528 return ipmi::response(ipmi::ccInvalidFieldRequest);
529 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800530 /*orignal OEM command is to record OEM SEL.
531 But openbmc does not support OEM SEL, so we redirect it to redfish event
532 logging. */
533 std::string buildInfo;
534 std::string action;
535 switch (FWUpdateTarget(target))
536 {
537 case FWUpdateTarget::targetBMC:
538 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700539 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800540 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
541 " BuildID: " + std::to_string(auxInfo);
542 buildInfo += std::to_string(auxInfo);
543 break;
544 case FWUpdateTarget::targetBIOS:
545 firmware = "BIOS";
546 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700547 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800548 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
549 " minor: " +
550 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
551 " ReleaseNumber: " + // ASCII encoded
552 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
553 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
554 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
555 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
556 break;
557 case FWUpdateTarget::targetME:
558 firmware = "ME";
559 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700560 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800561 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
562 " minor2: " +
563 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
564 " build1: " +
565 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
566 " build2: " +
567 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
568 break;
569 case FWUpdateTarget::targetOEMEWS:
570 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700571 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800572 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
573 " BuildID: " + std::to_string(auxInfo);
574 break;
575 }
576
Jason M. Billsdc249272019-04-03 09:58:40 -0700577 static const std::string openBMCMessageRegistryVersion("0.1");
578 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
579
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800580 switch (status)
581 {
582 case 0x0:
583 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700584 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800585 break;
586 case 0x1:
587 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700588 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800589 break;
590 case 0x2:
591 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700592 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800593 break;
594 default:
595 action = "unknown";
596 break;
597 }
598
Jason M. Billsdc249272019-04-03 09:58:40 -0700599 std::string firmwareInstanceStr =
600 firmware + " instance: " + std::to_string(instance);
601 std::string message("[firmware update] " + firmwareInstanceStr +
602 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800603
604 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700605 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
606 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
607 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800608 return ipmi::responseSuccess();
609}
610
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530611ipmi::RspType<uint8_t, std::vector<uint8_t>>
612 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
613 uint2_t slotNumber, uint3_t baseBoardSlotNum,
614 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
615 uint8_t netFn, uint8_t cmd,
616 std::optional<std::vector<uint8_t>> writeData)
617{
618 if (reserved1 || reserved2)
619 {
620 return ipmi::responseInvalidFieldRequest();
621 }
622
623 boost::system::error_code ec;
624 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
625 std::vector<uint8_t>>;
626 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
627 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
628 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
629 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
630 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
631 *writeData);
632 if (ec)
633 {
634 phosphor::logging::log<phosphor::logging::level::ERR>(
635 "Failed to call dbus method SlotIpmbRequest");
636 return ipmi::responseUnspecifiedError();
637 }
638
639 std::vector<uint8_t> dataReceived(0);
640 int status = -1;
641 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
642
643 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
644
645 if (status)
646 {
647 phosphor::logging::log<phosphor::logging::level::ERR>(
648 "Failed to get response from SlotIpmbRequest");
649 return ipmi::responseResponseError();
650 }
651 return ipmi::responseSuccess(cc, dataReceived);
652}
653
Jason M. Bills64796042018-10-03 16:51:55 -0700654ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
655 ipmi_request_t request,
656 ipmi_response_t response,
657 ipmi_data_len_t dataLen,
658 ipmi_context_t context)
659{
660 SetPowerRestoreDelayReq* data =
661 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
662 uint16_t delay = 0;
663
664 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
665 {
666 *dataLen = 0;
667 return IPMI_CC_REQ_DATA_LEN_INVALID;
668 }
669 delay = data->byteMSB;
670 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700671 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700672 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700673 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
674 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700675 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
676 *dataLen = 0;
677
678 return IPMI_CC_OK;
679}
680
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700681static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700682{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700683 static constexpr const char* cpuPresencePathPrefix =
684 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
685 static constexpr const char* cpuPresenceIntf =
686 "xyz.openbmc_project.Inventory.Item";
687 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
688 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
689 try
Jason M. Bills64796042018-10-03 16:51:55 -0700690 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700691 auto service =
692 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
693
694 ipmi::Value result = ipmi::getDbusProperty(
695 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
696 return std::get<bool>(result);
697 }
698 catch (const std::exception& e)
699 {
700 phosphor::logging::log<phosphor::logging::level::INFO>(
701 "Cannot find processor presence",
702 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
703 return false;
704 }
705}
706
707ipmi::RspType<bool, // CATERR Reset Enabled
708 bool, // ERR2 Reset Enabled
709 uint6_t, // reserved
710 uint8_t, // reserved, returns 0x3F
711 uint6_t, // CPU1 CATERR Count
712 uint2_t, // CPU1 Status
713 uint6_t, // CPU2 CATERR Count
714 uint2_t, // CPU2 Status
715 uint6_t, // CPU3 CATERR Count
716 uint2_t, // CPU3 Status
717 uint6_t, // CPU4 CATERR Count
718 uint2_t, // CPU4 Status
719 uint8_t // Crashdump Count
720 >
721 ipmiOEMGetProcessorErrConfig()
722{
723 bool resetOnCATERR = false;
724 bool resetOnERR2 = false;
725 uint6_t cpu1CATERRCount = 0;
726 uint6_t cpu2CATERRCount = 0;
727 uint6_t cpu3CATERRCount = 0;
728 uint6_t cpu4CATERRCount = 0;
729 uint8_t crashdumpCount = 0;
730 uint2_t cpu1Status =
731 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
732 uint2_t cpu2Status =
733 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
734 uint2_t cpu3Status =
735 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
736 uint2_t cpu4Status =
737 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
738
739 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
740 try
741 {
742 auto service = ipmi::getService(*busp, processorErrConfigIntf,
743 processorErrConfigObjPath);
744
745 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
746 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
747 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
748 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
749 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
750 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
751 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
752 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
753 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
754 }
755 catch (const std::exception& e)
756 {
757 phosphor::logging::log<phosphor::logging::level::ERR>(
758 "Failed to fetch processor error config",
759 phosphor::logging::entry("ERROR=%s", e.what()));
760 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700761 }
762
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700763 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
764 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
765 cpu2Status, cpu3CATERRCount, cpu3Status,
766 cpu4CATERRCount, cpu4Status, crashdumpCount);
767}
Jason M. Bills64796042018-10-03 16:51:55 -0700768
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700769ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
770 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
771 std::optional<bool> clearCPUErrorCount,
772 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
773{
774 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700775
776 try
777 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700778 auto service = ipmi::getService(*busp, processorErrConfigIntf,
779 processorErrConfigObjPath);
780 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
781 processorErrConfigIntf, "ResetOnCATERR",
782 resetOnCATERR);
783 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
784 processorErrConfigIntf, "ResetOnERR2",
785 resetOnERR2);
786 if (clearCPUErrorCount.value_or(false))
787 {
788 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700789 processorErrConfigIntf, "ErrorCountCPU1",
790 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700791 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700792 processorErrConfigIntf, "ErrorCountCPU2",
793 static_cast<uint8_t>(0));
794 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
795 processorErrConfigIntf, "ErrorCountCPU3",
796 static_cast<uint8_t>(0));
797 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
798 processorErrConfigIntf, "ErrorCountCPU4",
799 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700800 }
801 if (clearCrashdumpCount.value_or(false))
802 {
803 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700804 processorErrConfigIntf, "CrashdumpCount",
805 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700806 }
Jason M. Bills64796042018-10-03 16:51:55 -0700807 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700808 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700809 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800810 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700811 "Failed to set processor error config",
812 phosphor::logging::entry("EXCEPTION=%s", e.what()));
813 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700814 }
815
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700816 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700817}
818
Yong Li703922d2018-11-06 13:25:31 +0800819ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
820 ipmi_request_t request,
821 ipmi_response_t response,
822 ipmi_data_len_t dataLen,
823 ipmi_context_t context)
824{
825 GetOEMShutdownPolicyRes* resp =
826 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
827
828 if (*dataLen != 0)
829 {
830 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800831 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800832 *dataLen = 0;
833 return IPMI_CC_REQ_DATA_LEN_INVALID;
834 }
835
836 *dataLen = 0;
837
838 try
839 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700840 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800841 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700842 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
843 Value variant = getDbusProperty(
844 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
845 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800846
847 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
848 convertPolicyFromString(std::get<std::string>(variant)) ==
849 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
850 NoShutdownOnOCOT)
851 {
852 resp->policy = 0;
853 }
854 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
855 convertPolicyFromString(std::get<std::string>(variant)) ==
856 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
857 Policy::ShutdownOnOCOT)
858 {
859 resp->policy = 1;
860 }
861 else
862 {
863 phosphor::logging::log<phosphor::logging::level::ERR>(
864 "oem_set_shutdown_policy: invalid property!",
865 phosphor::logging::entry(
866 "PROP=%s", std::get<std::string>(variant).c_str()));
867 return IPMI_CC_UNSPECIFIED_ERROR;
868 }
Yong Li703922d2018-11-06 13:25:31 +0800869 // TODO needs to check if it is multi-node products,
870 // policy is only supported on node 3/4
871 resp->policySupport = shutdownPolicySupported;
872 }
873 catch (sdbusplus::exception_t& e)
874 {
875 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
876 return IPMI_CC_UNSPECIFIED_ERROR;
877 }
878
879 *dataLen = sizeof(GetOEMShutdownPolicyRes);
880 return IPMI_CC_OK;
881}
882
883ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
884 ipmi_request_t request,
885 ipmi_response_t response,
886 ipmi_data_len_t dataLen,
887 ipmi_context_t context)
888{
889 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800890 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
891 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
892 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800893
894 // TODO needs to check if it is multi-node products,
895 // policy is only supported on node 3/4
896 if (*dataLen != 1)
897 {
898 phosphor::logging::log<phosphor::logging::level::ERR>(
899 "oem_set_shutdown_policy: invalid input len!");
900 *dataLen = 0;
901 return IPMI_CC_REQ_DATA_LEN_INVALID;
902 }
903
904 *dataLen = 0;
905 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
906 {
907 phosphor::logging::log<phosphor::logging::level::ERR>(
908 "oem_set_shutdown_policy: invalid input!");
909 return IPMI_CC_INVALID_FIELD_REQUEST;
910 }
911
Yong Li0669d192019-05-06 14:01:46 +0800912 if (*req == noShutdownOnOCOT)
913 {
914 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
915 Policy::NoShutdownOnOCOT;
916 }
917 else
918 {
919 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
920 Policy::ShutdownOnOCOT;
921 }
922
Yong Li703922d2018-11-06 13:25:31 +0800923 try
924 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700925 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800926 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700927 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800928 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700929 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800930 oemShutdownPolicyObjPathProp,
931 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800932 }
933 catch (sdbusplus::exception_t& e)
934 {
935 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
936 return IPMI_CC_UNSPECIFIED_ERROR;
937 }
938
939 return IPMI_CC_OK;
940}
941
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530942/** @brief implementation for check the DHCP or not in IPv4
943 * @param[in] Channel - Channel number
944 * @returns true or false.
945 */
946static bool isDHCPEnabled(uint8_t Channel)
947{
948 try
949 {
950 auto ethdevice = getChannelName(Channel);
951 if (ethdevice.empty())
952 {
953 return false;
954 }
955 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700956 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530957 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700958 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
959 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530960 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700961 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530962 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
963 {
964 return true;
965 }
966 else
967 {
968 return false;
969 }
970 }
971 catch (sdbusplus::exception_t& e)
972 {
973 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
974 return true;
975 }
976}
977
978/** @brief implementes for check the DHCP or not in IPv6
979 * @param[in] Channel - Channel number
980 * @returns true or false.
981 */
982static bool isDHCPIPv6Enabled(uint8_t Channel)
983{
984
985 try
986 {
987 auto ethdevice = getChannelName(Channel);
988 if (ethdevice.empty())
989 {
990 return false;
991 }
992 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700993 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530994 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700995 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
996 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530997 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700998 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530999 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1000 {
1001 return true;
1002 }
1003 else
1004 {
1005 return false;
1006 }
1007 }
1008 catch (sdbusplus::exception_t& e)
1009 {
1010 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1011 return true;
1012 }
1013}
1014
1015/** @brief implementes the creating of default new user
1016 * @param[in] userName - new username in 16 bytes.
1017 * @param[in] userPassword - new password in 20 bytes
1018 * @returns ipmi completion code.
1019 */
1020ipmi::RspType<> ipmiOEMSetUser2Activation(
1021 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1022 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1023{
1024 bool userState = false;
1025 // Check for System Interface not exist and LAN should be static
1026 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1027 {
1028 ChannelInfo chInfo;
1029 try
1030 {
1031 getChannelInfo(channel, chInfo);
1032 }
1033 catch (sdbusplus::exception_t& e)
1034 {
1035 phosphor::logging::log<phosphor::logging::level::ERR>(
1036 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1037 phosphor::logging::entry("MSG: %s", e.description()));
1038 return ipmi::response(ipmi::ccUnspecifiedError);
1039 }
1040 if (chInfo.mediumType ==
1041 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1042 {
1043 phosphor::logging::log<phosphor::logging::level::ERR>(
1044 "ipmiOEMSetUser2Activation: system interface exist .");
1045 return ipmi::response(ipmi::ccCommandNotAvailable);
1046 }
1047 else
1048 {
1049
1050 if (chInfo.mediumType ==
1051 static_cast<uint8_t>(EChannelMediumType::lan8032))
1052 {
1053 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1054 {
1055 phosphor::logging::log<phosphor::logging::level::ERR>(
1056 "ipmiOEMSetUser2Activation: DHCP enabled .");
1057 return ipmi::response(ipmi::ccCommandNotAvailable);
1058 }
1059 }
1060 }
1061 }
1062 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1063 if (ipmi::ccSuccess ==
1064 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1065 {
1066 if (enabledUsers > 1)
1067 {
1068 phosphor::logging::log<phosphor::logging::level::ERR>(
1069 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1070 return ipmi::response(ipmi::ccCommandNotAvailable);
1071 }
1072 // Check the user 2 is enabled or not
1073 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1074 if (userState == true)
1075 {
1076 phosphor::logging::log<phosphor::logging::level::ERR>(
1077 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1078 return ipmi::response(ipmi::ccCommandNotAvailable);
1079 }
1080 }
1081 else
1082 {
1083 return ipmi::response(ipmi::ccUnspecifiedError);
1084 }
1085
1086#if BYTE_ORDER == LITTLE_ENDIAN
1087 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1088#endif
1089#if BYTE_ORDER == BIG_ENDIAN
1090 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1091#endif
1092
Vernon Mauery037cabd2020-05-14 12:16:01 -07001093 // ipmiUserSetUserName correctly handles char*, possibly non-null
1094 // terminated strings using ipmiMaxUserName size
1095 auto userNameRaw = reinterpret_cast<const char*>(userName.data());
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001096
Vernon Mauery037cabd2020-05-14 12:16:01 -07001097 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301098 {
1099 if (ipmi::ccSuccess ==
1100 ipmiUserSetUserPassword(
1101 ipmiDefaultUserId,
1102 reinterpret_cast<const char*>(userPassword.data())))
1103 {
1104 if (ipmi::ccSuccess ==
1105 ipmiUserSetPrivilegeAccess(
1106 ipmiDefaultUserId,
1107 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1108 privAccess, true))
1109 {
1110 phosphor::logging::log<phosphor::logging::level::INFO>(
1111 "ipmiOEMSetUser2Activation: user created successfully ");
1112 return ipmi::responseSuccess();
1113 }
1114 }
1115 // we need to delete the default user id which added in this command as
1116 // password / priv setting is failed.
1117 ipmiUserSetUserName(ipmiDefaultUserId, "");
1118 phosphor::logging::log<phosphor::logging::level::ERR>(
1119 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1120 }
1121 else
1122 {
1123 phosphor::logging::log<phosphor::logging::level::ERR>(
1124 "ipmiOEMSetUser2Activation: Setting username failed.");
1125 }
1126
1127 return ipmi::response(ipmi::ccCommandNotAvailable);
1128}
1129
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301130/** @brief implementes executing the linux command
1131 * @param[in] linux command
1132 * @returns status
1133 */
1134
1135static uint8_t executeCmd(const char* path)
1136{
1137 boost::process::child execProg(path);
1138 execProg.wait();
1139
1140 int retCode = execProg.exit_code();
1141 if (retCode)
1142 {
1143 return ipmi::ccUnspecifiedError;
1144 }
1145 return ipmi::ccSuccess;
1146}
1147
1148/** @brief implementes ASD Security event logging
1149 * @param[in] Event message string
1150 * @param[in] Event Severity
1151 * @returns status
1152 */
1153
1154static void atScaleDebugEventlog(std::string msg, int severity)
1155{
1156 std::string eventStr = "OpenBMC.0.1." + msg;
1157 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1158 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1159 eventStr.c_str(), NULL);
1160}
1161
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301162/** @brief implementes setting password for special user
1163 * @param[in] specialUserIndex
1164 * @param[in] userPassword - new password in 20 bytes
1165 * @returns ipmi completion code.
1166 */
1167ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1168 uint8_t specialUserIndex,
1169 std::vector<uint8_t> userPassword)
1170{
1171 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301172 ipmi_ret_t status = ipmi::ccSuccess;
1173
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301174 try
1175 {
1176 getChannelInfo(ctx->channel, chInfo);
1177 }
1178 catch (sdbusplus::exception_t& e)
1179 {
1180 phosphor::logging::log<phosphor::logging::level::ERR>(
1181 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1182 phosphor::logging::entry("MSG: %s", e.description()));
1183 return ipmi::responseUnspecifiedError();
1184 }
1185 if (chInfo.mediumType !=
1186 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1187 {
1188 phosphor::logging::log<phosphor::logging::level::ERR>(
1189 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1190 "interface");
1191 return ipmi::responseCommandNotAvailable();
1192 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301193
1194 // 0 for root user and 1 for AtScaleDebug is allowed
1195 if (specialUserIndex >
1196 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301197 {
1198 phosphor::logging::log<phosphor::logging::level::ERR>(
1199 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1200 return ipmi::responseParmOutOfRange();
1201 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301202 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301203 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301204 constexpr uint8_t minPasswordSizeRequired = 6;
1205 std::string passwd;
1206 if (userPassword.size() < minPasswordSizeRequired ||
1207 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1208 {
1209 return ipmi::responseReqDataLenInvalid();
1210 }
1211 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1212 userPassword.size());
1213 if (specialUserIndex ==
1214 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1215 {
1216 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1217
1218 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1219 }
1220 else
1221 {
1222 status = ipmiSetSpecialUserPassword("root", passwd);
1223 }
1224 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301225 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301226 else
1227 {
1228 if (specialUserIndex ==
1229 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1230 {
1231 status = executeCmd("passwd -d root");
1232 }
1233 else
1234 {
1235
1236 status = executeCmd("passwd -d asdbg");
1237
1238 if (status == 0)
1239 {
1240 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1241 LOG_INFO);
1242 }
1243 }
1244 return ipmi::response(status);
1245 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301246}
1247
Kuiying Wang45f04982018-12-26 09:23:08 +08001248namespace ledAction
1249{
1250using namespace sdbusplus::xyz::openbmc_project::Led::server;
1251std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001252 {Physical::Action::Off, 0},
1253 {Physical::Action::On, 2},
1254 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001255
1256std::map<uint8_t, std::string> offsetObjPath = {
1257 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1258
1259} // namespace ledAction
1260
1261int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1262 const std::string& objPath, uint8_t& state)
1263{
1264 try
1265 {
1266 std::string service = getService(bus, intf, objPath);
1267 Value stateValue =
1268 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001269 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001270 state = ledAction::actionDbusToIpmi.at(
1271 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1272 convertActionFromString(strState));
1273 }
1274 catch (sdbusplus::exception::SdBusError& e)
1275 {
1276 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1277 return -1;
1278 }
1279 return 0;
1280}
1281
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001282ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001283{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001284 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001285 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001286 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001287 for (auto it = ledAction::offsetObjPath.begin();
1288 it != ledAction::offsetObjPath.end(); ++it)
1289 {
1290 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001291 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001292 {
1293 phosphor::logging::log<phosphor::logging::level::ERR>(
1294 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001295 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001296 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001297 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001298 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001299 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001300}
1301
Yong Li23737fe2019-02-19 08:49:55 +08001302ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1303 ipmi_request_t request,
1304 ipmi_response_t response,
1305 ipmi_data_len_t dataLen,
1306 ipmi_context_t context)
1307{
1308 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1309 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1310
1311 if (*dataLen == 0)
1312 {
1313 phosphor::logging::log<phosphor::logging::level::ERR>(
1314 "CfgHostSerial: invalid input len!",
1315 phosphor::logging::entry("LEN=%d", *dataLen));
1316 return IPMI_CC_REQ_DATA_LEN_INVALID;
1317 }
1318
1319 switch (req->command)
1320 {
1321 case getHostSerialCfgCmd:
1322 {
1323 if (*dataLen != 1)
1324 {
1325 phosphor::logging::log<phosphor::logging::level::ERR>(
1326 "CfgHostSerial: invalid input len!");
1327 *dataLen = 0;
1328 return IPMI_CC_REQ_DATA_LEN_INVALID;
1329 }
1330
1331 *dataLen = 0;
1332
1333 boost::process::ipstream is;
1334 std::vector<std::string> data;
1335 std::string line;
1336 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1337 boost::process::std_out > is);
1338
1339 while (c1.running() && std::getline(is, line) && !line.empty())
1340 {
1341 data.push_back(line);
1342 }
1343
1344 c1.wait();
1345 if (c1.exit_code())
1346 {
1347 phosphor::logging::log<phosphor::logging::level::ERR>(
1348 "CfgHostSerial:: error on execute",
1349 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1350 // Using the default value
1351 *resp = 0;
1352 }
1353 else
1354 {
1355 if (data.size() != 1)
1356 {
1357 phosphor::logging::log<phosphor::logging::level::ERR>(
1358 "CfgHostSerial:: error on read env");
1359 return IPMI_CC_UNSPECIFIED_ERROR;
1360 }
1361 try
1362 {
1363 unsigned long tmp = std::stoul(data[0]);
1364 if (tmp > std::numeric_limits<uint8_t>::max())
1365 {
1366 throw std::out_of_range("Out of range");
1367 }
1368 *resp = static_cast<uint8_t>(tmp);
1369 }
1370 catch (const std::invalid_argument& e)
1371 {
1372 phosphor::logging::log<phosphor::logging::level::ERR>(
1373 "invalid config ",
1374 phosphor::logging::entry("ERR=%s", e.what()));
1375 return IPMI_CC_UNSPECIFIED_ERROR;
1376 }
1377 catch (const std::out_of_range& e)
1378 {
1379 phosphor::logging::log<phosphor::logging::level::ERR>(
1380 "out_of_range config ",
1381 phosphor::logging::entry("ERR=%s", e.what()));
1382 return IPMI_CC_UNSPECIFIED_ERROR;
1383 }
1384 }
1385
1386 *dataLen = 1;
1387 break;
1388 }
1389 case setHostSerialCfgCmd:
1390 {
1391 if (*dataLen != sizeof(CfgHostSerialReq))
1392 {
1393 phosphor::logging::log<phosphor::logging::level::ERR>(
1394 "CfgHostSerial: invalid input len!");
1395 *dataLen = 0;
1396 return IPMI_CC_REQ_DATA_LEN_INVALID;
1397 }
1398
1399 *dataLen = 0;
1400
1401 if (req->parameter > HostSerialCfgParamMax)
1402 {
1403 phosphor::logging::log<phosphor::logging::level::ERR>(
1404 "CfgHostSerial: invalid input!");
1405 return IPMI_CC_INVALID_FIELD_REQUEST;
1406 }
1407
1408 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1409 std::to_string(req->parameter));
1410
1411 c1.wait();
1412 if (c1.exit_code())
1413 {
1414 phosphor::logging::log<phosphor::logging::level::ERR>(
1415 "CfgHostSerial:: error on execute",
1416 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1417 return IPMI_CC_UNSPECIFIED_ERROR;
1418 }
1419 break;
1420 }
1421 default:
1422 phosphor::logging::log<phosphor::logging::level::ERR>(
1423 "CfgHostSerial: invalid input!");
1424 *dataLen = 0;
1425 return IPMI_CC_INVALID_FIELD_REQUEST;
1426 }
1427
1428 return IPMI_CC_OK;
1429}
1430
James Feist91244a62019-02-19 15:04:54 -08001431constexpr const char* thermalModeInterface =
1432 "xyz.openbmc_project.Control.ThermalMode";
1433constexpr const char* thermalModePath =
1434 "/xyz/openbmc_project/control/thermal_mode";
1435
1436bool getFanProfileInterface(
1437 sdbusplus::bus::bus& bus,
1438 boost::container::flat_map<
1439 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1440{
1441 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1442 "GetAll");
1443 call.append(thermalModeInterface);
1444 try
1445 {
1446 auto data = bus.call(call);
1447 data.read(resp);
1448 }
1449 catch (sdbusplus::exception_t& e)
1450 {
1451 phosphor::logging::log<phosphor::logging::level::ERR>(
1452 "getFanProfileInterface: can't get thermal mode!",
1453 phosphor::logging::entry("ERR=%s", e.what()));
1454 return false;
1455 }
1456 return true;
1457}
1458
anil kumar appanaf945eee2019-09-25 23:29:11 +00001459/**@brief implements the OEM set fan config.
1460 * @param selectedFanProfile - fan profile to enable
1461 * @param reserved1
1462 * @param performanceMode - Performance/Acoustic mode
1463 * @param reserved2
1464 * @param setPerformanceMode - set Performance/Acoustic mode
1465 * @param setFanProfile - set fan profile
1466 *
1467 * @return IPMI completion code.
1468 **/
1469ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1470
1471 uint2_t reserved1, bool performanceMode,
1472 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301473 bool setFanProfile,
1474 std::optional<uint8_t> dimmGroupId,
1475 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001476{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001477 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001478 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001479 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001480 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301481
1482 if (dimmGroupId)
1483 {
1484 if (*dimmGroupId >= maxCPUNum)
1485 {
1486 return ipmi::responseInvalidFieldRequest();
1487 }
1488 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1489 {
1490 return ipmi::responseInvalidFieldRequest();
1491 }
1492 }
1493
James Feist91244a62019-02-19 15:04:54 -08001494 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001495 boost::container::flat_map<
1496 std::string, std::variant<std::vector<std::string>, std::string>>
1497 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001498 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1499 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001500 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001501 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001502 }
1503
1504 std::vector<std::string>* supported =
1505 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1506 if (supported == nullptr)
1507 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001508 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001509 }
1510 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001511 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001512 {
James Feist91244a62019-02-19 15:04:54 -08001513 if (performanceMode)
1514 {
1515
1516 if (std::find(supported->begin(), supported->end(),
1517 "Performance") != supported->end())
1518 {
1519 mode = "Performance";
1520 }
1521 }
1522 else
1523 {
James Feist91244a62019-02-19 15:04:54 -08001524 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1525 supported->end())
1526 {
1527 mode = "Acoustic";
1528 }
1529 }
1530 if (mode.empty())
1531 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001532 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001533 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001534
1535 try
1536 {
1537 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1538 thermalModeInterface, "Current", mode);
1539 }
1540 catch (sdbusplus::exception_t& e)
1541 {
1542 phosphor::logging::log<phosphor::logging::level::ERR>(
1543 "ipmiOEMSetFanConfig: can't set thermal mode!",
1544 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1545 return ipmi::responseResponseError();
1546 }
James Feist91244a62019-02-19 15:04:54 -08001547 }
1548
anil kumar appanaf945eee2019-09-25 23:29:11 +00001549 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001550}
1551
James Feist5b693632019-07-09 09:06:09 -07001552ipmi::RspType<uint8_t, // profile support map
1553 uint8_t, // fan control profile enable
1554 uint8_t, // flags
1555 uint32_t // dimm presence bit map
1556 >
1557 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001558{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301559 if (dimmGroupId >= maxCPUNum)
1560 {
1561 return ipmi::responseInvalidFieldRequest();
1562 }
1563
1564 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1565
1566 if (!cpuStatus)
1567 {
1568 return ipmi::responseInvalidFieldRequest();
1569 }
1570
James Feist91244a62019-02-19 15:04:54 -08001571 boost::container::flat_map<
1572 std::string, std::variant<std::vector<std::string>, std::string>>
1573 profileData;
1574
Vernon Mauery15419dd2019-05-24 09:40:30 -07001575 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1576 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001577 {
James Feist5b693632019-07-09 09:06:09 -07001578 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001579 }
1580
1581 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1582
1583 if (current == nullptr)
1584 {
1585 phosphor::logging::log<phosphor::logging::level::ERR>(
1586 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001587 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001588 }
1589 bool performance = (*current == "Performance");
1590
James Feist5b693632019-07-09 09:06:09 -07001591 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001592 if (performance)
1593 {
James Feist5b693632019-07-09 09:06:09 -07001594 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001595 }
1596
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001597 constexpr uint8_t fanControlDefaultProfile = 0x80;
1598 constexpr uint8_t fanControlProfileState = 0x00;
1599 constexpr uint32_t dimmPresenceBitmap = 0x00;
1600
1601 return ipmi::responseSuccess(fanControlDefaultProfile,
1602 fanControlProfileState, flags,
1603 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001604}
James Feist5f957ca2019-03-14 15:33:55 -07001605constexpr const char* cfmLimitSettingPath =
1606 "/xyz/openbmc_project/control/cfm_limit";
1607constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001608constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001609constexpr const size_t legacyPCHSensorNumber = 0x22;
1610constexpr const char* exitAirPathName = "Exit_Air";
1611constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001612constexpr const char* pidConfigurationIface =
1613 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001614
James Feist09f6b602019-08-08 11:30:03 -07001615static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001616{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001617 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001618 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001619 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1620 "/xyz/openbmc_project/object_mapper",
1621 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001622
James Feistacc8a4e2019-04-02 14:23:57 -07001623 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001624 std::string path;
1625 GetSubTreeType resp;
1626 try
1627 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001628 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001629 reply.read(resp);
1630 }
1631 catch (sdbusplus::exception_t&)
1632 {
1633 phosphor::logging::log<phosphor::logging::level::ERR>(
1634 "ipmiOEMGetFscParameter: mapper error");
1635 };
James Feist09f6b602019-08-08 11:30:03 -07001636 auto config =
1637 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1638 return pair.first.find(name) != std::string::npos;
1639 });
James Feistfaa4f222019-03-21 16:21:55 -07001640 if (config != resp.end())
1641 {
1642 path = std::move(config->first);
1643 }
1644 return path;
1645}
James Feist5f957ca2019-03-14 15:33:55 -07001646
James Feistacc8a4e2019-04-02 14:23:57 -07001647// flat map to make alphabetical
1648static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1649{
1650 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001651 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001652 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001653 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1654 "/xyz/openbmc_project/object_mapper",
1655 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001656
1657 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1658 GetSubTreeType resp;
1659
1660 try
1661 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001662 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001663 reply.read(resp);
1664 }
1665 catch (sdbusplus::exception_t&)
1666 {
1667 phosphor::logging::log<phosphor::logging::level::ERR>(
1668 "getFanConfigPaths: mapper error");
1669 };
1670 for (const auto& [path, objects] : resp)
1671 {
1672 if (objects.empty())
1673 {
1674 continue; // should be impossible
1675 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001676
1677 try
1678 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001679 ret.emplace(path,
1680 getAllDbusProperties(*dbus, objects[0].first, path,
1681 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001682 }
1683 catch (sdbusplus::exception_t& e)
1684 {
1685 phosphor::logging::log<phosphor::logging::level::ERR>(
1686 "getPidConfigs: can't get DbusProperties!",
1687 phosphor::logging::entry("ERR=%s", e.what()));
1688 }
James Feistacc8a4e2019-04-02 14:23:57 -07001689 }
1690 return ret;
1691}
1692
1693ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1694{
1695 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1696 if (data.empty())
1697 {
1698 return ipmi::responseResponseError();
1699 }
1700 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1701 for (const auto& [_, pid] : data)
1702 {
1703 auto findClass = pid.find("Class");
1704 if (findClass == pid.end())
1705 {
1706 phosphor::logging::log<phosphor::logging::level::ERR>(
1707 "ipmiOEMGetFscParameter: found illegal pid "
1708 "configurations");
1709 return ipmi::responseResponseError();
1710 }
1711 std::string type = std::get<std::string>(findClass->second);
1712 if (type == "fan")
1713 {
1714 auto findOutLimit = pid.find("OutLimitMin");
1715 if (findOutLimit == pid.end())
1716 {
1717 phosphor::logging::log<phosphor::logging::level::ERR>(
1718 "ipmiOEMGetFscParameter: found illegal pid "
1719 "configurations");
1720 return ipmi::responseResponseError();
1721 }
1722 // get the min out of all the offsets
1723 minOffset = std::min(
1724 minOffset,
1725 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1726 }
1727 }
1728 if (minOffset == std::numeric_limits<uint8_t>::max())
1729 {
1730 phosphor::logging::log<phosphor::logging::level::ERR>(
1731 "ipmiOEMGetFscParameter: found no fan configurations!");
1732 return ipmi::responseResponseError();
1733 }
1734
1735 return ipmi::responseSuccess(minOffset);
1736}
1737
1738ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1739{
1740 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1741 if (data.empty())
1742 {
1743
1744 phosphor::logging::log<phosphor::logging::level::ERR>(
1745 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1746 return ipmi::responseResponseError();
1747 }
1748
Vernon Mauery15419dd2019-05-24 09:40:30 -07001749 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001750 bool found = false;
1751 for (const auto& [path, pid] : data)
1752 {
1753 auto findClass = pid.find("Class");
1754 if (findClass == pid.end())
1755 {
1756
1757 phosphor::logging::log<phosphor::logging::level::ERR>(
1758 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1759 "configurations");
1760 return ipmi::responseResponseError();
1761 }
1762 std::string type = std::get<std::string>(findClass->second);
1763 if (type == "fan")
1764 {
1765 auto findOutLimit = pid.find("OutLimitMin");
1766 if (findOutLimit == pid.end())
1767 {
1768
1769 phosphor::logging::log<phosphor::logging::level::ERR>(
1770 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1771 "configurations");
1772 return ipmi::responseResponseError();
1773 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001774 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001775 path, pidConfigurationIface, "OutLimitMin",
1776 static_cast<double>(offset));
1777 found = true;
1778 }
1779 }
1780 if (!found)
1781 {
1782 phosphor::logging::log<phosphor::logging::level::ERR>(
1783 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1784 return ipmi::responseResponseError();
1785 }
1786
1787 return ipmi::responseSuccess();
1788}
1789
1790ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1791 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001792{
1793 constexpr const size_t disableLimiting = 0x0;
1794
Vernon Mauery15419dd2019-05-24 09:40:30 -07001795 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001796 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001797 {
James Feist09f6b602019-08-08 11:30:03 -07001798 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001799 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001800 {
James Feist09f6b602019-08-08 11:30:03 -07001801 pathName = exitAirPathName;
1802 }
1803 else if (param1 == legacyPCHSensorNumber)
1804 {
1805 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001806 }
1807 else
1808 {
James Feistacc8a4e2019-04-02 14:23:57 -07001809 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001810 }
James Feist09f6b602019-08-08 11:30:03 -07001811 std::string path = getConfigPath(pathName);
1812 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1813 pidConfigurationIface, "SetPoint",
1814 static_cast<double>(param2));
1815 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001816 }
James Feistacc8a4e2019-04-02 14:23:57 -07001817 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001818 {
James Feistacc8a4e2019-04-02 14:23:57 -07001819 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001820
1821 // must be greater than 50 based on eps
1822 if (cfm < 50 && cfm != disableLimiting)
1823 {
James Feistacc8a4e2019-04-02 14:23:57 -07001824 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001825 }
1826
1827 try
1828 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001829 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001830 cfmLimitIface, "Limit",
1831 static_cast<double>(cfm));
1832 }
1833 catch (sdbusplus::exception_t& e)
1834 {
1835 phosphor::logging::log<phosphor::logging::level::ERR>(
1836 "ipmiOEMSetFscParameter: can't set cfm setting!",
1837 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001838 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001839 }
James Feistacc8a4e2019-04-02 14:23:57 -07001840 return ipmi::responseSuccess();
1841 }
1842 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1843 {
1844 constexpr const size_t maxDomainCount = 8;
1845 uint8_t requestedDomainMask = param1;
1846 boost::container::flat_map data = getPidConfigs();
1847 if (data.empty())
1848 {
1849
1850 phosphor::logging::log<phosphor::logging::level::ERR>(
1851 "ipmiOEMSetFscParameter: found no pid configurations!");
1852 return ipmi::responseResponseError();
1853 }
1854 size_t count = 0;
1855 for (const auto& [path, pid] : data)
1856 {
1857 auto findClass = pid.find("Class");
1858 if (findClass == pid.end())
1859 {
1860
1861 phosphor::logging::log<phosphor::logging::level::ERR>(
1862 "ipmiOEMSetFscParameter: found illegal pid "
1863 "configurations");
1864 return ipmi::responseResponseError();
1865 }
1866 std::string type = std::get<std::string>(findClass->second);
1867 if (type == "fan")
1868 {
1869 if (requestedDomainMask & (1 << count))
1870 {
1871 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001872 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001873 pidConfigurationIface, "OutLimitMax",
1874 static_cast<double>(param2));
1875 }
1876 count++;
1877 }
1878 }
1879 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001880 }
1881 else
1882 {
1883 // todo other command parts possibly
1884 // tcontrol is handled in peci now
1885 // fan speed offset not implemented yet
1886 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001887 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001888 }
1889}
1890
James Feistacc8a4e2019-04-02 14:23:57 -07001891ipmi::RspType<
1892 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1893 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001894{
James Feist09f6b602019-08-08 11:30:03 -07001895 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001896
Vernon Mauery15419dd2019-05-24 09:40:30 -07001897 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001898 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001899 {
James Feistacc8a4e2019-04-02 14:23:57 -07001900 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001901 {
James Feistacc8a4e2019-04-02 14:23:57 -07001902 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001903 }
1904
James Feist09f6b602019-08-08 11:30:03 -07001905 std::string pathName;
1906
1907 if (*param == legacyExitAirSensorNumber)
1908 {
1909 pathName = exitAirPathName;
1910 }
1911 else if (*param == legacyPCHSensorNumber)
1912 {
1913 pathName = pchPathName;
1914 }
1915 else
James Feistfaa4f222019-03-21 16:21:55 -07001916 {
James Feistacc8a4e2019-04-02 14:23:57 -07001917 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001918 }
James Feist09f6b602019-08-08 11:30:03 -07001919
1920 uint8_t setpoint = legacyDefaultSetpoint;
1921 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001922 if (path.size())
1923 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001924 Value val = ipmi::getDbusProperty(
1925 *dbus, "xyz.openbmc_project.EntityManager", path,
1926 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001927 setpoint = std::floor(std::get<double>(val) + 0.5);
1928 }
1929
1930 // old implementation used to return the "default" and current, we
1931 // don't make the default readily available so just make both the
1932 // same
James Feistfaa4f222019-03-21 16:21:55 -07001933
James Feistacc8a4e2019-04-02 14:23:57 -07001934 return ipmi::responseSuccess(
1935 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001936 }
James Feistacc8a4e2019-04-02 14:23:57 -07001937 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1938 {
1939 constexpr const size_t maxDomainCount = 8;
1940
1941 if (!param)
1942 {
1943 return ipmi::responseReqDataLenInvalid();
1944 }
1945 uint8_t requestedDomain = *param;
1946 if (requestedDomain >= maxDomainCount)
1947 {
1948 return ipmi::responseInvalidFieldRequest();
1949 }
1950
1951 boost::container::flat_map data = getPidConfigs();
1952 if (data.empty())
1953 {
1954 phosphor::logging::log<phosphor::logging::level::ERR>(
1955 "ipmiOEMGetFscParameter: found no pid configurations!");
1956 return ipmi::responseResponseError();
1957 }
1958 size_t count = 0;
1959 for (const auto& [_, pid] : data)
1960 {
1961 auto findClass = pid.find("Class");
1962 if (findClass == pid.end())
1963 {
1964 phosphor::logging::log<phosphor::logging::level::ERR>(
1965 "ipmiOEMGetFscParameter: found illegal pid "
1966 "configurations");
1967 return ipmi::responseResponseError();
1968 }
1969 std::string type = std::get<std::string>(findClass->second);
1970 if (type == "fan")
1971 {
1972 if (requestedDomain == count)
1973 {
1974 auto findOutLimit = pid.find("OutLimitMax");
1975 if (findOutLimit == pid.end())
1976 {
1977 phosphor::logging::log<phosphor::logging::level::ERR>(
1978 "ipmiOEMGetFscParameter: found illegal pid "
1979 "configurations");
1980 return ipmi::responseResponseError();
1981 }
1982
1983 return ipmi::responseSuccess(
1984 static_cast<uint8_t>(std::floor(
1985 std::get<double>(findOutLimit->second) + 0.5)));
1986 }
1987 else
1988 {
1989 count++;
1990 }
1991 }
1992 }
1993
1994 return ipmi::responseInvalidFieldRequest();
1995 }
1996 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001997 {
1998
1999 /*
2000 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002001 previous behavior didn't seem to prevent this, ignore the check for
2002 now.
James Feist5f957ca2019-03-14 15:33:55 -07002003
James Feistacc8a4e2019-04-02 14:23:57 -07002004 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002005 {
2006 phosphor::logging::log<phosphor::logging::level::ERR>(
2007 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002008 return IPMI_CC_REQ_DATA_LEN_INVALID;
2009 }
2010 */
2011 Value cfmLimit;
2012 Value cfmMaximum;
2013 try
2014 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002015 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002016 cfmLimitSettingPath, cfmLimitIface,
2017 "Limit");
2018 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002019 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002020 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2021 }
2022 catch (sdbusplus::exception_t& e)
2023 {
2024 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002025 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002026 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002027 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002028 }
2029
James Feistacc8a4e2019-04-02 14:23:57 -07002030 double cfmMax = std::get<double>(cfmMaximum);
2031 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002032
James Feistacc8a4e2019-04-02 14:23:57 -07002033 cfmLim = std::floor(cfmLim + 0.5);
2034 cfmMax = std::floor(cfmMax + 0.5);
2035 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2036 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002037
James Feistacc8a4e2019-04-02 14:23:57 -07002038 return ipmi::responseSuccess(
2039 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002040 }
James Feistacc8a4e2019-04-02 14:23:57 -07002041
James Feist5f957ca2019-03-14 15:33:55 -07002042 else
2043 {
2044 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002045 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002046 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002047 }
2048}
2049
Cheng C Yang773703a2019-08-15 09:41:11 +08002050using crConfigVariant =
2051 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2052
2053int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2054 const crConfigVariant& value,
2055 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2056{
2057 boost::system::error_code ec;
2058 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002059 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002060 "/xyz/openbmc_project/control/power_supply_redundancy",
2061 "org.freedesktop.DBus.Properties", "Set",
2062 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2063 if (ec)
2064 {
2065 phosphor::logging::log<phosphor::logging::level::ERR>(
2066 "Failed to set dbus property to cold redundancy");
2067 return -1;
2068 }
2069
2070 return 0;
2071}
2072
2073int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2074 crConfigVariant& value,
Yong Li19445ab2019-12-20 18:25:29 +08002075 const std::string& service = "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002076 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2077{
2078 boost::system::error_code ec;
2079 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002080 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002081 "/xyz/openbmc_project/control/power_supply_redundancy",
2082 "org.freedesktop.DBus.Properties", "Get",
2083 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2084 if (ec)
2085 {
2086 phosphor::logging::log<phosphor::logging::level::ERR>(
2087 "Failed to get dbus property to cold redundancy");
2088 return -1;
2089 }
2090 return 0;
2091}
2092
2093uint8_t getPSUCount(void)
2094{
2095 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2096 ipmi::Value num;
2097 try
2098 {
2099 num = ipmi::getDbusProperty(
2100 *dbus, "xyz.openbmc_project.PSURedundancy",
2101 "/xyz/openbmc_project/control/power_supply_redundancy",
2102 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2103 }
2104 catch (sdbusplus::exception_t& e)
2105 {
2106 phosphor::logging::log<phosphor::logging::level::ERR>(
2107 "Failed to get PSUNumber property from dbus interface");
2108 return 0;
2109 }
2110 uint8_t* pNum = std::get_if<uint8_t>(&num);
2111 if (!pNum)
2112 {
2113 phosphor::logging::log<phosphor::logging::level::ERR>(
2114 "Error to get PSU Number");
2115 return 0;
2116 }
2117 return *pNum;
2118}
2119
2120bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2121{
2122 if (conf.size() < num)
2123 {
2124 phosphor::logging::log<phosphor::logging::level::ERR>(
2125 "Invalid PSU Ranking");
2126 return false;
2127 }
2128 std::set<uint8_t> confSet;
2129 for (uint8_t i = 0; i < num; i++)
2130 {
2131 if (conf[i] > num)
2132 {
2133 phosphor::logging::log<phosphor::logging::level::ERR>(
2134 "PSU Ranking is larger than current PSU number");
2135 return false;
2136 }
2137 confSet.emplace(conf[i]);
2138 }
2139
2140 if (confSet.size() != num)
2141 {
2142 phosphor::logging::log<phosphor::logging::level::ERR>(
2143 "duplicate PSU Ranking");
2144 return false;
2145 }
2146 return true;
2147}
2148
2149enum class crParameter
2150{
2151 crStatus = 0,
2152 crFeature = 1,
2153 rotationFeature = 2,
2154 rotationAlgo = 3,
2155 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002156 numOfPSU = 5,
2157 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002158};
2159
2160constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2161static const constexpr uint32_t oneDay = 0x15180;
2162static const constexpr uint32_t oneMonth = 0xf53700;
2163static const constexpr uint8_t userSpecific = 0x01;
2164static const constexpr uint8_t crSetCompleted = 0;
2165ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2166 uint8_t parameter,
2167 ipmi::message::Payload& payload)
2168{
2169 switch (static_cast<crParameter>(parameter))
2170 {
2171 case crParameter::crFeature:
2172 {
2173 uint8_t param1;
2174 if (payload.unpack(param1) || !payload.fullyUnpacked())
2175 {
2176 return ipmi::responseReqDataLenInvalid();
2177 }
2178 // ColdRedundancy Enable can only be true or flase
2179 if (param1 > 1)
2180 {
2181 return ipmi::responseInvalidFieldRequest();
2182 }
2183 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2184 static_cast<bool>(param1)))
2185 {
2186 return ipmi::responseResponseError();
2187 }
2188 break;
2189 }
2190 case crParameter::rotationFeature:
2191 {
2192 uint8_t param1;
2193 if (payload.unpack(param1) || !payload.fullyUnpacked())
2194 {
2195 return ipmi::responseReqDataLenInvalid();
2196 }
2197 // Rotation Enable can only be true or false
2198 if (param1 > 1)
2199 {
2200 return ipmi::responseInvalidFieldRequest();
2201 }
2202 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2203 {
2204 return ipmi::responseResponseError();
2205 }
2206 break;
2207 }
2208 case crParameter::rotationAlgo:
2209 {
2210 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2211 std::string algoName;
2212 uint8_t param1;
2213 if (payload.unpack(param1))
2214 {
2215 return ipmi::responseReqDataLenInvalid();
2216 }
2217 switch (param1)
2218 {
2219 case 0:
2220 algoName = "xyz.openbmc_project.Control."
2221 "PowerSupplyRedundancy.Algo.bmcSpecific";
2222 break;
2223 case 1:
2224 algoName = "xyz.openbmc_project.Control."
2225 "PowerSupplyRedundancy.Algo.userSpecific";
2226 break;
2227 default:
2228 return ipmi::responseInvalidFieldRequest();
2229 }
2230 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2231 {
2232 return ipmi::responseResponseError();
2233 }
2234
2235 uint8_t numberOfPSU = getPSUCount();
2236 if (!numberOfPSU)
2237 {
2238 return ipmi::responseResponseError();
2239 }
2240 std::vector<uint8_t> rankOrder;
2241
2242 if (param1 == userSpecific)
2243 {
2244 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2245 {
2246 ipmi::responseReqDataLenInvalid();
2247 }
Yong Li83315132019-10-23 17:42:24 +08002248 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002249 {
2250 return ipmi::responseReqDataLenInvalid();
2251 }
2252
2253 if (!validateCRAlgo(rankOrder, numberOfPSU))
2254 {
2255 return ipmi::responseInvalidFieldRequest();
2256 }
2257 }
2258 else
2259 {
2260 if (rankOrder.size() > 0)
2261 {
2262 return ipmi::responseReqDataLenInvalid();
2263 }
2264 for (uint8_t i = 1; i <= numberOfPSU; i++)
2265 {
2266 rankOrder.emplace_back(i);
2267 }
2268 }
2269 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2270 {
2271 return ipmi::responseResponseError();
2272 }
2273 break;
2274 }
2275 case crParameter::rotationPeriod:
2276 {
2277 // Minimum Rotation period is One day (86400 seconds) and Max
2278 // Rotation Period is 6 month (0xf53700 seconds)
2279 uint32_t period;
2280 if (payload.unpack(period) || !payload.fullyUnpacked())
2281 {
2282 return ipmi::responseReqDataLenInvalid();
2283 }
2284 if ((period < oneDay) || (period > oneMonth))
2285 {
2286 return ipmi::responseInvalidFieldRequest();
2287 }
2288 if (setCRConfig(ctx, "PeriodOfRotation", period))
2289 {
2290 return ipmi::responseResponseError();
2291 }
2292 break;
2293 }
2294 default:
2295 {
2296 return ipmi::response(ccParameterNotSupported);
2297 }
2298 }
2299
2300 // TODO Halfwidth needs to set SetInProgress
2301 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002302 std::string("xyz.openbmc_project.Control."
2303 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002304 {
2305 return ipmi::responseResponseError();
2306 }
2307 return ipmi::responseSuccess(crSetCompleted);
2308}
2309
Yong Li83315132019-10-23 17:42:24 +08002310ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002311 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2312{
2313 crConfigVariant value;
2314 switch (static_cast<crParameter>(parameter))
2315 {
2316 case crParameter::crStatus:
2317 {
2318 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2319 {
2320 return ipmi::responseResponseError();
2321 }
2322 std::string* pStatus = std::get_if<std::string>(&value);
2323 if (!pStatus)
2324 {
2325 phosphor::logging::log<phosphor::logging::level::ERR>(
2326 "Error to get ColdRedundancyStatus property");
2327 return ipmi::responseResponseError();
2328 }
2329 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2330 auto status =
2331 server::PowerSupplyRedundancy::convertStatusFromString(
2332 *pStatus);
2333 switch (status)
2334 {
2335 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002336 return ipmi::responseSuccess(parameter,
2337 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002338
2339 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002340 return ipmi::responseSuccess(parameter,
2341 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002342 default:
2343 phosphor::logging::log<phosphor::logging::level::ERR>(
2344 "Error to get valid status");
2345 return ipmi::responseResponseError();
2346 }
2347 }
2348 case crParameter::crFeature:
2349 {
2350 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2351 {
2352 return ipmi::responseResponseError();
2353 }
2354 bool* pResponse = std::get_if<bool>(&value);
2355 if (!pResponse)
2356 {
2357 phosphor::logging::log<phosphor::logging::level::ERR>(
2358 "Error to get ColdRedundancyEnable property");
2359 return ipmi::responseResponseError();
2360 }
2361
Cheng C Yangf41e3342019-09-10 04:47:23 +08002362 return ipmi::responseSuccess(parameter,
2363 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002364 }
2365 case crParameter::rotationFeature:
2366 {
2367 if (getCRConfig(ctx, "RotationEnabled", value))
2368 {
2369 return ipmi::responseResponseError();
2370 }
2371 bool* pResponse = std::get_if<bool>(&value);
2372 if (!pResponse)
2373 {
2374 phosphor::logging::log<phosphor::logging::level::ERR>(
2375 "Error to get RotationEnabled property");
2376 return ipmi::responseResponseError();
2377 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002378 return ipmi::responseSuccess(parameter,
2379 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002380 }
2381 case crParameter::rotationAlgo:
2382 {
2383 if (getCRConfig(ctx, "RotationAlgorithm", value))
2384 {
2385 return ipmi::responseResponseError();
2386 }
2387
2388 std::string* pAlgo = std::get_if<std::string>(&value);
2389 if (!pAlgo)
2390 {
2391 phosphor::logging::log<phosphor::logging::level::ERR>(
2392 "Error to get RotationAlgorithm property");
2393 return ipmi::responseResponseError();
2394 }
Yong Li83315132019-10-23 17:42:24 +08002395 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002396 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2397 auto algo =
2398 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002399
Cheng C Yang773703a2019-08-15 09:41:11 +08002400 switch (algo)
2401 {
2402 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002403 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002404 break;
2405 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002406 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002407 break;
2408 default:
2409 phosphor::logging::log<phosphor::logging::level::ERR>(
2410 "Error to get valid algo");
2411 return ipmi::responseResponseError();
2412 }
2413
2414 if (getCRConfig(ctx, "RotationRankOrder", value))
2415 {
2416 return ipmi::responseResponseError();
2417 }
2418 std::vector<uint8_t>* pResponse =
2419 std::get_if<std::vector<uint8_t>>(&value);
2420 if (!pResponse)
2421 {
2422 phosphor::logging::log<phosphor::logging::level::ERR>(
2423 "Error to get RotationRankOrder property");
2424 return ipmi::responseResponseError();
2425 }
Yong Li83315132019-10-23 17:42:24 +08002426
Cheng C Yang773703a2019-08-15 09:41:11 +08002427 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002428 std::back_inserter(response));
2429
Cheng C Yangf41e3342019-09-10 04:47:23 +08002430 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002431 }
2432 case crParameter::rotationPeriod:
2433 {
2434 if (getCRConfig(ctx, "PeriodOfRotation", value))
2435 {
2436 return ipmi::responseResponseError();
2437 }
2438 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2439 if (!pResponse)
2440 {
2441 phosphor::logging::log<phosphor::logging::level::ERR>(
2442 "Error to get RotationAlgorithm property");
2443 return ipmi::responseResponseError();
2444 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002445 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002446 }
2447 case crParameter::numOfPSU:
2448 {
2449 uint8_t numberOfPSU = getPSUCount();
2450 if (!numberOfPSU)
2451 {
2452 return ipmi::responseResponseError();
2453 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002454 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002455 }
Yong Li19445ab2019-12-20 18:25:29 +08002456 case crParameter::rotationRankOrderEffective:
2457 {
2458 if (getCRConfig(ctx, "RotationRankOrder", value,
2459 "xyz.openbmc_project.PSURedundancy"))
2460 {
2461 return ipmi::responseResponseError();
2462 }
2463 std::vector<uint8_t>* pResponse =
2464 std::get_if<std::vector<uint8_t>>(&value);
2465 if (!pResponse)
2466 {
2467 phosphor::logging::log<phosphor::logging::level::ERR>(
2468 "Error to get effective RotationRankOrder property");
2469 return ipmi::responseResponseError();
2470 }
2471 return ipmi::responseSuccess(parameter, *pResponse);
2472 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002473 default:
2474 {
2475 return ipmi::response(ccParameterNotSupported);
2476 }
2477 }
2478}
2479
Zhu, Yungebe560b02019-04-21 21:19:21 -04002480ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2481 uint8_t faultState,
2482 uint8_t faultGroup,
2483 std::array<uint8_t, 8>& ledStateData)
2484{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002485 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2486 static const std::array<std::string, maxFaultType> faultNames = {
2487 "faultFan", "faultTemp", "faultPower",
2488 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002489
2490 constexpr uint8_t maxFaultSource = 0x4;
2491 constexpr uint8_t skipLEDs = 0xFF;
2492 constexpr uint8_t pinSize = 64;
2493 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002494 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002495
Zhikui Rence4e73f2019-12-06 13:59:47 -08002496 // same pin names need to be defined in dts file
2497 static const std::array<std::array<std::string, groupSize>, groupNum>
2498 faultLedPinNames = {{
2499 "LED_CPU1_CH1_DIMM1_FAULT",
2500 "LED_CPU1_CH1_DIMM2_FAULT",
2501 "LED_CPU1_CH2_DIMM1_FAULT",
2502 "LED_CPU1_CH2_DIMM2_FAULT",
2503 "LED_CPU1_CH3_DIMM1_FAULT",
2504 "LED_CPU1_CH3_DIMM2_FAULT",
2505 "LED_CPU1_CH4_DIMM1_FAULT",
2506 "LED_CPU1_CH4_DIMM2_FAULT",
2507 "LED_CPU1_CH5_DIMM1_FAULT",
2508 "LED_CPU1_CH5_DIMM2_FAULT",
2509 "LED_CPU1_CH6_DIMM1_FAULT",
2510 "LED_CPU1_CH6_DIMM2_FAULT",
2511 "",
2512 "",
2513 "",
2514 "", // end of group1
2515 "LED_CPU2_CH1_DIMM1_FAULT",
2516 "LED_CPU2_CH1_DIMM2_FAULT",
2517 "LED_CPU2_CH2_DIMM1_FAULT",
2518 "LED_CPU2_CH2_DIMM2_FAULT",
2519 "LED_CPU2_CH3_DIMM1_FAULT",
2520 "LED_CPU2_CH3_DIMM2_FAULT",
2521 "LED_CPU2_CH4_DIMM1_FAULT",
2522 "LED_CPU2_CH4_DIMM2_FAULT",
2523 "LED_CPU2_CH5_DIMM1_FAULT",
2524 "LED_CPU2_CH5_DIMM2_FAULT",
2525 "LED_CPU2_CH6_DIMM1_FAULT",
2526 "LED_CPU2_CH6_DIMM2_FAULT",
2527 "",
2528 "",
2529 "",
2530 "", // endof group2
2531 "LED_CPU3_CH1_DIMM1_FAULT",
2532 "LED_CPU3_CH1_DIMM2_FAULT",
2533 "LED_CPU3_CH2_DIMM1_FAULT",
2534 "LED_CPU3_CH2_DIMM2_FAULT",
2535 "LED_CPU3_CH3_DIMM1_FAULT",
2536 "LED_CPU3_CH3_DIMM2_FAULT",
2537 "LED_CPU3_CH4_DIMM1_FAULT",
2538 "LED_CPU3_CH4_DIMM2_FAULT",
2539 "LED_CPU3_CH5_DIMM1_FAULT",
2540 "LED_CPU3_CH5_DIMM2_FAULT",
2541 "LED_CPU3_CH6_DIMM1_FAULT",
2542 "LED_CPU3_CH6_DIMM2_FAULT",
2543 "",
2544 "",
2545 "",
2546 "", // end of group3
2547 "LED_CPU4_CH1_DIMM1_FAULT",
2548 "LED_CPU4_CH1_DIMM2_FAULT",
2549 "LED_CPU4_CH2_DIMM1_FAULT",
2550 "LED_CPU4_CH2_DIMM2_FAULT",
2551 "LED_CPU4_CH3_DIMM1_FAULT",
2552 "LED_CPU4_CH3_DIMM2_FAULT",
2553 "LED_CPU4_CH4_DIMM1_FAULT",
2554 "LED_CPU4_CH4_DIMM2_FAULT",
2555 "LED_CPU4_CH5_DIMM1_FAULT",
2556 "LED_CPU4_CH5_DIMM2_FAULT",
2557 "LED_CPU4_CH6_DIMM1_FAULT",
2558 "LED_CPU4_CH6_DIMM2_FAULT",
2559 "",
2560 "",
2561 "",
2562 "", // end of group4
2563 "LED_FAN1_FAULT",
2564 "LED_FAN2_FAULT",
2565 "LED_FAN3_FAULT",
2566 "LED_FAN4_FAULT",
2567 "LED_FAN5_FAULT",
2568 "LED_FAN6_FAULT",
2569 "LED_FAN7_FAULT",
2570 "LED_FAN8_FAULT",
2571 "",
2572 "",
2573 "",
2574 "",
2575 "",
2576 "",
2577 "",
2578 "" // end of group5
2579 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002580
Zhikui Rence4e73f2019-12-06 13:59:47 -08002581 // Validate the source, fault type --
2582 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2583 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2584 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2585 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2586 // definition differs based on fault type (Byte 2)
2587 // Type Fan=> Group: 0=FanGroupID, FF-not used
2588 // Byte 5-11 00h, not used
2589 // Byte12 FanLedState [7:0]-Fans 7:0
2590 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2591 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2592 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2593 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2594 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2595 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2596 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2597 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002598 if ((sourceId >= maxFaultSource) ||
2599 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2600 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2601 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2602 {
2603 return ipmi::responseParmOutOfRange();
2604 }
2605
Zhikui Rence4e73f2019-12-06 13:59:47 -08002606 size_t pinGroupOffset = 0;
2607 size_t pinGroupMax = pinSize / groupSize;
2608 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002609 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002610 pinGroupOffset = 4;
2611 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002612 }
2613
2614 switch (RemoteFaultType(faultType))
2615 {
2616 case (RemoteFaultType::fan):
2617 case (RemoteFaultType::memory):
2618 {
2619 if (faultGroup == skipLEDs)
2620 {
2621 return ipmi::responseSuccess();
2622 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002623 // calculate led state bit filed count, each byte has 8bits
2624 // the maximum bits will be 8 * 8 bits
2625 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002626
2627 // assemble ledState
2628 uint64_t ledState = 0;
2629 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002630 for (int i = 0; i < sizeof(ledStateData); i++)
2631 {
2632 ledState = (uint64_t)(ledState << 8);
2633 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2634 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002635 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002636
Zhikui Rence4e73f2019-12-06 13:59:47 -08002637 for (int group = 0; group < pinGroupMax; group++)
2638 {
2639 for (int i = 0; i < groupSize; i++)
2640 { // skip non-existing pins
2641 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2642 {
2643 continue;
2644 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002645
Zhikui Rence4e73f2019-12-06 13:59:47 -08002646 gpiod::line line = gpiod::find_line(
2647 faultLedPinNames[group + pinGroupOffset][i]);
2648 if (!line)
2649 {
2650 phosphor::logging::log<phosphor::logging::level::ERR>(
2651 "Not Find Led Gpio Device!",
2652 phosphor::logging::entry(
2653 "DEVICE=%s",
2654 faultLedPinNames[group + pinGroupOffset][i]
2655 .c_str()));
2656 hasError = true;
2657 continue;
2658 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002659
Zhikui Rence4e73f2019-12-06 13:59:47 -08002660 bool activeHigh =
2661 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2662 try
2663 {
2664 line.request(
2665 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2666 activeHigh
2667 ? 0
2668 : gpiod::line_request::FLAG_ACTIVE_LOW});
2669 line.set_value(ledStateBits[i + group * groupSize]);
2670 }
2671 catch (std::system_error&)
2672 {
2673 phosphor::logging::log<phosphor::logging::level::ERR>(
2674 "Error write Led Gpio Device!",
2675 phosphor::logging::entry(
2676 "DEVICE=%s",
2677 faultLedPinNames[group + pinGroupOffset][i]
2678 .c_str()));
2679 hasError = true;
2680 continue;
2681 }
2682 } // for int i
2683 }
2684 if (hasError)
2685 {
2686 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002687 }
2688 break;
2689 }
2690 default:
2691 {
2692 // now only support two fault types
2693 return ipmi::responseParmOutOfRange();
2694 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002695 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002696 return ipmi::responseSuccess();
2697}
2698
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302699ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2700{
2701 uint8_t prodId = 0;
2702 try
2703 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002704 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302705 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002706 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302707 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2708 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002709 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302710 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2711 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302712 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2713 }
2714 catch (std::exception& e)
2715 {
2716 phosphor::logging::log<phosphor::logging::level::ERR>(
2717 "ipmiOEMReadBoardProductId: Product ID read failed!",
2718 phosphor::logging::entry("ERR=%s", e.what()));
2719 }
2720 return ipmi::responseSuccess(prodId);
2721}
2722
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302723/** @brief implements the get security mode command
2724 * @param ctx - ctx pointer
2725 *
2726 * @returns IPMI completion code with following data
2727 * - restriction mode value - As specified in
2728 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2729 * - special mode value - As specified in
2730 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2731 */
2732ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2733{
2734 namespace securityNameSpace =
2735 sdbusplus::xyz::openbmc_project::Control::Security::server;
2736 uint8_t restrictionModeValue = 0;
2737 uint8_t specialModeValue = 0;
2738
2739 boost::system::error_code ec;
2740 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002741 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302742 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2743 restricionModeProperty);
2744 if (ec)
2745 {
2746 phosphor::logging::log<phosphor::logging::level::ERR>(
2747 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2748 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2749 return ipmi::responseUnspecifiedError();
2750 }
2751 restrictionModeValue = static_cast<uint8_t>(
2752 securityNameSpace::RestrictionMode::convertModesFromString(
2753 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302754 auto varSpecialMode =
2755 ctx->bus->yield_method_call<std::variant<std::string>>(
2756 ctx->yield, ec, specialModeService, specialModeBasePath,
2757 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2758 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302759 if (ec)
2760 {
2761 phosphor::logging::log<phosphor::logging::level::ERR>(
2762 "ipmiGetSecurityMode: failed to get SpecialMode property",
2763 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2764 // fall through, let us not worry about SpecialMode property, which is
2765 // not required in user scenario
2766 }
2767 else
2768 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302769 specialModeValue = static_cast<uint8_t>(
2770 securityNameSpace::SpecialMode::convertModesFromString(
2771 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302772 }
2773 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2774}
2775
2776/** @brief implements the set security mode command
2777 * Command allows to upgrade the restriction mode and won't allow
2778 * to downgrade from system interface
2779 * @param ctx - ctx pointer
2780 * @param restrictionMode - restriction mode value to be set.
2781 *
2782 * @returns IPMI completion code
2783 */
2784ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302785 uint8_t restrictionMode,
2786 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302787{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302788#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2789 if (specialMode)
2790 {
2791 return ipmi::responseReqDataLenInvalid();
2792 }
2793#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302794 namespace securityNameSpace =
2795 sdbusplus::xyz::openbmc_project::Control::Security::server;
2796
2797 ChannelInfo chInfo;
2798 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2799 {
2800 phosphor::logging::log<phosphor::logging::level::ERR>(
2801 "ipmiSetSecurityMode: Failed to get Channel Info",
2802 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2803 return ipmi::responseUnspecifiedError();
2804 }
2805 auto reqMode =
2806 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2807
2808 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2809 (reqMode >
2810 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2811 {
2812 return ipmi::responseInvalidFieldRequest();
2813 }
2814
2815 boost::system::error_code ec;
2816 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002817 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302818 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2819 restricionModeProperty);
2820 if (ec)
2821 {
2822 phosphor::logging::log<phosphor::logging::level::ERR>(
2823 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2824 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2825 return ipmi::responseUnspecifiedError();
2826 }
2827 auto currentRestrictionMode =
2828 securityNameSpace::RestrictionMode::convertModesFromString(
2829 std::get<std::string>(varRestrMode));
2830
2831 if (chInfo.mediumType !=
2832 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2833 currentRestrictionMode > reqMode)
2834 {
2835 phosphor::logging::log<phosphor::logging::level::ERR>(
2836 "ipmiSetSecurityMode - Downgrading security mode not supported "
2837 "through system interface",
2838 phosphor::logging::entry(
2839 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2840 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2841 return ipmi::responseCommandNotAvailable();
2842 }
2843
2844 ec.clear();
2845 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002846 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302847 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2848 restricionModeProperty,
2849 static_cast<std::variant<std::string>>(
2850 securityNameSpace::convertForMessage(reqMode)));
2851
2852 if (ec)
2853 {
2854 phosphor::logging::log<phosphor::logging::level::ERR>(
2855 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2856 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2857 return ipmi::responseUnspecifiedError();
2858 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302859
2860#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2861 if (specialMode)
2862 {
2863 ec.clear();
2864 ctx->bus->yield_method_call<>(
2865 ctx->yield, ec, specialModeService, specialModeBasePath,
2866 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2867 specialModeProperty,
2868 static_cast<std::variant<std::string>>(
2869 securityNameSpace::convertForMessage(
2870 static_cast<securityNameSpace::SpecialMode::Modes>(
2871 specialMode.value()))));
2872
2873 if (ec)
2874 {
2875 phosphor::logging::log<phosphor::logging::level::ERR>(
2876 "ipmiSetSecurityMode: failed to set SpecialMode property",
2877 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2878 return ipmi::responseUnspecifiedError();
2879 }
2880 }
2881#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302882 return ipmi::responseSuccess();
2883}
2884
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002885ipmi::RspType<uint8_t /* restore status */>
2886 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2887{
2888 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2889
2890 if (clr != expClr)
2891 {
2892 return ipmi::responseInvalidFieldRequest();
2893 }
2894 constexpr uint8_t cmdStatus = 0;
2895 constexpr uint8_t cmdDefaultRestore = 0xaa;
2896 constexpr uint8_t cmdFullRestore = 0xbb;
2897 constexpr uint8_t cmdFormat = 0xcc;
2898
2899 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2900
2901 switch (cmd)
2902 {
2903 case cmdStatus:
2904 break;
2905 case cmdDefaultRestore:
2906 case cmdFullRestore:
2907 case cmdFormat:
2908 {
2909 // write file to rwfs root
2910 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2911 std::ofstream restoreFile(restoreOpFname);
2912 if (!restoreFile)
2913 {
2914 return ipmi::responseUnspecifiedError();
2915 }
2916 restoreFile << value << "\n";
2917 break;
2918 }
2919 default:
2920 return ipmi::responseInvalidFieldRequest();
2921 }
2922
2923 constexpr uint8_t restorePending = 0;
2924 constexpr uint8_t restoreComplete = 1;
2925
2926 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2927 ? restorePending
2928 : restoreComplete;
2929 return ipmi::responseSuccess(restoreStatus);
2930}
2931
Chen Yugang39736d52019-07-12 16:24:33 +08002932ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2933{
2934 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002935 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002936
2937 try
2938 {
2939 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2940 std::string service =
2941 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2942 Value variant =
2943 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2944 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2945
2946 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2947 std::get<std::string>(variant)))
2948 {
2949 case nmi::NMISource::BMCSourceSignal::None:
2950 bmcSource = static_cast<uint8_t>(NmiSource::none);
2951 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002952 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2953 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002954 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002955 case nmi::NMISource::BMCSourceSignal::Watchdog:
2956 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002957 break;
2958 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2959 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2960 break;
2961 case nmi::NMISource::BMCSourceSignal::MemoryError:
2962 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2963 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002964 case nmi::NMISource::BMCSourceSignal::PciBusError:
2965 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002966 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002967 case nmi::NMISource::BMCSourceSignal::PCH:
2968 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002969 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002970 case nmi::NMISource::BMCSourceSignal::Chipset:
2971 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002972 break;
2973 default:
2974 phosphor::logging::log<phosphor::logging::level::ERR>(
2975 "NMI source: invalid property!",
2976 phosphor::logging::entry(
2977 "PROP=%s", std::get<std::string>(variant).c_str()));
2978 return ipmi::responseResponseError();
2979 }
2980 }
2981 catch (sdbusplus::exception::SdBusError& e)
2982 {
2983 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2984 return ipmi::responseResponseError();
2985 }
2986
2987 return ipmi::responseSuccess(bmcSource);
2988}
2989
2990ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2991{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002992 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002993
2994 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2995 nmi::NMISource::BMCSourceSignal::None;
2996
2997 switch (NmiSource(sourceId))
2998 {
2999 case NmiSource::none:
3000 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3001 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003002 case NmiSource::frontPanelButton:
3003 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003004 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003005 case NmiSource::watchdog:
3006 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003007 break;
3008 case NmiSource::chassisCmd:
3009 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3010 break;
3011 case NmiSource::memoryError:
3012 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3013 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003014 case NmiSource::pciBusError:
3015 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003016 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003017 case NmiSource::pch:
3018 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003019 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003020 case NmiSource::chipset:
3021 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003022 break;
3023 default:
3024 phosphor::logging::log<phosphor::logging::level::ERR>(
3025 "NMI source: invalid property!");
3026 return ipmi::responseResponseError();
3027 }
3028
3029 try
3030 {
3031 // keep NMI signal source
3032 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3033 std::string service =
3034 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003035 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3036 oemNmiBmcSourceObjPathProp,
3037 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003038 // set Enabled property to inform NMI source handling
3039 // to trigger a NMI_OUT BSOD.
3040 // if it's triggered by NMI source property changed,
3041 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3042 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3043 {
3044 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3045 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3046 static_cast<bool>(true));
3047 }
Chen Yugang39736d52019-07-12 16:24:33 +08003048 }
3049 catch (sdbusplus::exception_t& e)
3050 {
3051 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3052 return ipmi::responseResponseError();
3053 }
3054
3055 return ipmi::responseSuccess();
3056}
3057
James Feist63efafa2019-07-24 12:39:21 -07003058namespace dimmOffset
3059{
3060constexpr const char* dimmPower = "DimmPower";
3061constexpr const char* staticCltt = "StaticCltt";
3062constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3063constexpr const char* offsetInterface =
3064 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3065constexpr const char* property = "DimmOffset";
3066
3067}; // namespace dimmOffset
3068
3069ipmi::RspType<>
3070 ipmiOEMSetDimmOffset(uint8_t type,
3071 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3072{
3073 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3074 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3075 {
3076 return ipmi::responseInvalidFieldRequest();
3077 }
3078
3079 if (data.empty())
3080 {
3081 return ipmi::responseInvalidFieldRequest();
3082 }
3083 nlohmann::json json;
3084
3085 std::ifstream jsonStream(dimmOffsetFile);
3086 if (jsonStream.good())
3087 {
3088 json = nlohmann::json::parse(jsonStream, nullptr, false);
3089 if (json.is_discarded())
3090 {
3091 json = nlohmann::json();
3092 }
3093 jsonStream.close();
3094 }
3095
3096 std::string typeName;
3097 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3098 {
3099 typeName = dimmOffset::dimmPower;
3100 }
3101 else
3102 {
3103 typeName = dimmOffset::staticCltt;
3104 }
3105
3106 nlohmann::json& field = json[typeName];
3107
3108 for (const auto& [index, value] : data)
3109 {
3110 field[index] = value;
3111 }
3112
3113 for (nlohmann::json& val : field)
3114 {
3115 if (val == nullptr)
3116 {
3117 val = static_cast<uint8_t>(0);
3118 }
3119 }
3120
3121 std::ofstream output(dimmOffsetFile);
3122 if (!output.good())
3123 {
3124 std::cerr << "Error writing json file\n";
3125 return ipmi::responseResponseError();
3126 }
3127
3128 output << json.dump(4);
3129
3130 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3131 {
3132 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3133
3134 std::variant<std::vector<uint8_t>> offsets =
3135 field.get<std::vector<uint8_t>>();
3136 auto call = bus->new_method_call(
3137 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3138 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3139 try
3140 {
3141 bus->call(call);
3142 }
3143 catch (sdbusplus::exception_t& e)
3144 {
3145 phosphor::logging::log<phosphor::logging::level::ERR>(
3146 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3147 phosphor::logging::entry("ERR=%s", e.what()));
3148 return ipmi::responseResponseError();
3149 }
3150 }
3151
3152 return ipmi::responseSuccess();
3153}
3154
3155ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3156{
3157
3158 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3159 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3160 {
3161 return ipmi::responseInvalidFieldRequest();
3162 }
3163
3164 std::ifstream jsonStream(dimmOffsetFile);
3165
3166 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3167 if (json.is_discarded())
3168 {
3169 std::cerr << "File error in " << dimmOffsetFile << "\n";
3170 return ipmi::responseResponseError();
3171 }
3172
3173 std::string typeName;
3174 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3175 {
3176 typeName = dimmOffset::dimmPower;
3177 }
3178 else
3179 {
3180 typeName = dimmOffset::staticCltt;
3181 }
3182
3183 auto it = json.find(typeName);
3184 if (it == json.end())
3185 {
3186 return ipmi::responseInvalidFieldRequest();
3187 }
3188
3189 if (it->size() <= index)
3190 {
3191 return ipmi::responseInvalidFieldRequest();
3192 }
3193
3194 uint8_t resp = it->at(index).get<uint8_t>();
3195 return ipmi::responseSuccess(resp);
3196}
3197
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003198namespace boot_options
3199{
3200
3201using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3202using IpmiValue = uint8_t;
3203constexpr auto ipmiDefault = 0;
3204
3205std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3206 {0x01, Source::Sources::Network},
3207 {0x02, Source::Sources::Disk},
3208 {0x05, Source::Sources::ExternalMedia},
3209 {0x0f, Source::Sources::RemovableMedia},
3210 {ipmiDefault, Source::Sources::Default}};
3211
3212std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003213 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003214
3215std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3216 {Source::Sources::Network, 0x01},
3217 {Source::Sources::Disk, 0x02},
3218 {Source::Sources::ExternalMedia, 0x05},
3219 {Source::Sources::RemovableMedia, 0x0f},
3220 {Source::Sources::Default, ipmiDefault}};
3221
3222std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003223 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003224
3225static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3226static constexpr auto bootSourceIntf =
3227 "xyz.openbmc_project.Control.Boot.Source";
3228static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3229static constexpr auto persistentObjPath =
3230 "/xyz/openbmc_project/control/host0/boot";
3231static constexpr auto oneTimePath =
3232 "/xyz/openbmc_project/control/host0/boot/one_time";
3233static constexpr auto bootSourceProp = "BootSource";
3234static constexpr auto bootModeProp = "BootMode";
3235static constexpr auto oneTimeBootEnableProp = "Enabled";
3236static constexpr auto httpBootMode =
3237 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3238
3239enum class BootOptionParameter : size_t
3240{
3241 setInProgress = 0x0,
3242 bootFlags = 0x5,
3243};
3244static constexpr uint8_t setComplete = 0x0;
3245static constexpr uint8_t setInProgress = 0x1;
3246static uint8_t transferStatus = setComplete;
3247static constexpr uint8_t setParmVersion = 0x01;
3248static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3249static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3250static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3251static constexpr uint8_t httpBoot = 0xd;
3252static constexpr uint8_t bootSourceMask = 0x3c;
3253
3254} // namespace boot_options
3255
3256ipmi::RspType<uint8_t, // version
3257 uint8_t, // param
3258 uint8_t, // data0, dependent on parameter
3259 std::optional<uint8_t> // data1, dependent on parameter
3260 >
3261 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3262{
3263 using namespace boot_options;
3264 uint8_t bootOption = 0;
3265
3266 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3267 {
3268 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3269 std::nullopt);
3270 }
3271
3272 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3273 {
3274 phosphor::logging::log<phosphor::logging::level::ERR>(
3275 "Unsupported parameter");
3276 return ipmi::responseResponseError();
3277 }
3278
3279 try
3280 {
3281 auto oneTimeEnabled = false;
3282 // read one time Enabled property
3283 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3284 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3285 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3286 enabledIntf, oneTimeBootEnableProp);
3287 oneTimeEnabled = std::get<bool>(variant);
3288
3289 // get BootSource and BootMode properties
3290 // according to oneTimeEnable
3291 auto bootObjPath = oneTimePath;
3292 if (oneTimeEnabled == false)
3293 {
3294 bootObjPath = persistentObjPath;
3295 }
3296
3297 service = getService(*dbus, bootModeIntf, bootObjPath);
3298 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3299 bootModeProp);
3300
3301 auto bootMode =
3302 Mode::convertModesFromString(std::get<std::string>(variant));
3303
3304 service = getService(*dbus, bootSourceIntf, bootObjPath);
3305 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3306 bootSourceProp);
3307
3308 if (std::get<std::string>(variant) == httpBootMode)
3309 {
3310 bootOption = httpBoot;
3311 }
3312 else
3313 {
3314 auto bootSource = Source::convertSourcesFromString(
3315 std::get<std::string>(variant));
3316 bootOption = sourceDbusToIpmi.at(bootSource);
3317 if (Source::Sources::Default == bootSource)
3318 {
3319 bootOption = modeDbusToIpmi.at(bootMode);
3320 }
3321 }
3322
3323 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3324 : setParmBootFlagsValidPermanent;
3325 bootOption <<= 2; // shift for responseconstexpr
3326 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3327 bootOption);
3328 }
3329 catch (sdbusplus::exception_t& e)
3330 {
3331 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3332 return ipmi::responseResponseError();
3333 }
3334}
3335
3336ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3337 std::optional<uint8_t> bootOption)
3338{
3339 using namespace boot_options;
3340 auto oneTimeEnabled = false;
3341
3342 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3343 {
3344 if (bootOption)
3345 {
3346 return ipmi::responseReqDataLenInvalid();
3347 }
3348
3349 if (transferStatus == setInProgress)
3350 {
3351 phosphor::logging::log<phosphor::logging::level::ERR>(
3352 "boot option set in progress!");
3353 return ipmi::responseResponseError();
3354 }
3355
3356 transferStatus = bootParam;
3357 return ipmi::responseSuccess();
3358 }
3359
3360 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3361 {
3362 phosphor::logging::log<phosphor::logging::level::ERR>(
3363 "Unsupported parameter");
3364 return ipmi::responseResponseError();
3365 }
3366
3367 if (!bootOption)
3368 {
3369 return ipmi::responseReqDataLenInvalid();
3370 }
3371
3372 if (((bootOption.value() & bootSourceMask) >> 2) !=
3373 httpBoot) // not http boot, exit
3374 {
3375 phosphor::logging::log<phosphor::logging::level::ERR>(
3376 "wrong boot option parameter!");
3377 return ipmi::responseParmOutOfRange();
3378 }
3379
3380 try
3381 {
3382 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3383 setParmBootFlagsPermanent;
3384
3385 // read one time Enabled property
3386 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3387 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3388 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3389 enabledIntf, oneTimeBootEnableProp);
3390 oneTimeEnabled = std::get<bool>(variant);
3391
3392 /*
3393 * Check if the current boot setting is onetime or permanent, if the
3394 * request in the command is otherwise, then set the "Enabled"
3395 * property in one_time object path to 'True' to indicate onetime
3396 * and 'False' to indicate permanent.
3397 *
3398 * Once the onetime/permanent setting is applied, then the bootMode
3399 * and bootSource is updated for the corresponding object.
3400 */
3401 if (permanent == oneTimeEnabled)
3402 {
3403 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3404 oneTimeBootEnableProp, !permanent);
3405 }
3406
3407 // set BootSource and BootMode properties
3408 // according to oneTimeEnable or persistent
3409 auto bootObjPath = oneTimePath;
3410 if (oneTimeEnabled == false)
3411 {
3412 bootObjPath = persistentObjPath;
3413 }
3414 std::string bootMode =
3415 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3416 std::string bootSource = httpBootMode;
3417
3418 service = getService(*dbus, bootModeIntf, bootObjPath);
3419 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3420 bootMode);
3421
3422 service = getService(*dbus, bootSourceIntf, bootObjPath);
3423 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3424 bootSourceProp, bootSource);
3425 }
3426 catch (sdbusplus::exception_t& e)
3427 {
3428 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3429 return ipmi::responseResponseError();
3430 }
3431
3432 return ipmi::responseSuccess();
3433}
3434
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003435using BasicVariantType =
3436 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3437 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3438 uint16_t, uint8_t, bool>;
3439using PropertyMapType =
3440 boost::container::flat_map<std::string, BasicVariantType>;
3441static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3442 "xyz.openbmc_project.Configuration.PSUPresence"};
3443int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3444 std::vector<uint64_t>& addrTable)
3445{
3446 boost::system::error_code ec;
3447 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3448 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3449 "/xyz/openbmc_project/object_mapper",
3450 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3451 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3452 if (ec)
3453 {
3454 phosphor::logging::log<phosphor::logging::level::ERR>(
3455 "Failed to set dbus property to cold redundancy");
3456 return -1;
3457 }
3458 for (const auto& object : subtree)
3459 {
3460 std::string pathName = object.first;
3461 for (const auto& serviceIface : object.second)
3462 {
3463 std::string serviceName = serviceIface.first;
3464
3465 ec.clear();
3466 PropertyMapType propMap =
3467 ctx->bus->yield_method_call<PropertyMapType>(
3468 ctx->yield, ec, serviceName, pathName,
3469 "org.freedesktop.DBus.Properties", "GetAll",
3470 "xyz.openbmc_project.Configuration.PSUPresence");
3471 if (ec)
3472 {
3473 phosphor::logging::log<phosphor::logging::level::ERR>(
3474 "Failed to set dbus property to cold redundancy");
3475 return -1;
3476 }
3477 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3478 auto psuAddress =
3479 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3480
3481 if (psuBus == nullptr || psuAddress == nullptr)
3482 {
3483 std::cerr << "error finding necessary "
3484 "entry in configuration\n";
3485 return -1;
3486 }
3487 bus = static_cast<uint8_t>(*psuBus);
3488 addrTable = *psuAddress;
3489 return 0;
3490 }
3491 }
3492 return -1;
3493}
3494
3495static const constexpr uint8_t addrOffset = 8;
3496static const constexpr uint8_t psuRevision = 0xd9;
3497static const constexpr uint8_t defaultPSUBus = 7;
3498// Second Minor, Primary Minor, Major
3499static const constexpr size_t verLen = 3;
3500ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3501{
3502 uint8_t bus = defaultPSUBus;
3503 std::vector<uint64_t> addrTable;
3504 std::vector<uint8_t> result;
3505 if (getPSUAddress(ctx, bus, addrTable))
3506 {
3507 std::cerr << "Failed to get PSU bus and address\n";
3508 return ipmi::responseResponseError();
3509 }
3510
3511 for (const auto& slaveAddr : addrTable)
3512 {
3513 std::vector<uint8_t> writeData = {psuRevision};
3514 std::vector<uint8_t> readBuf(verLen);
3515 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3516 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3517
3518 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3519 if (retI2C != ipmi::ccSuccess)
3520 {
3521 for (size_t idx = 0; idx < verLen; idx++)
3522 {
3523 result.emplace_back(0x00);
3524 }
3525 }
3526 else
3527 {
3528 for (const uint8_t& data : readBuf)
3529 {
3530 result.emplace_back(data);
3531 }
3532 }
3533 }
3534
3535 return ipmi::responseSuccess(result);
3536}
3537
AppaRao Puli28972062019-11-11 02:04:45 +05303538/** @brief implements the maximum size of
3539 * bridgeable messages used between KCS and
3540 * IPMB interfacesget security mode command.
3541 *
3542 * @returns IPMI completion code with following data
3543 * - KCS Buffer Size (In multiples of four bytes)
3544 * - IPMB Buffer Size (In multiples of four bytes)
3545 **/
3546ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3547{
3548 // for now this is hard coded; really this number is dependent on
3549 // the BMC kcs driver as well as the host kcs driver....
3550 // we can't know the latter.
3551 uint8_t kcsMaxBufferSize = 63 / 4;
3552 uint8_t ipmbMaxBufferSize = 128 / 4;
3553
3554 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3555}
3556
Jason M. Bills64796042018-10-03 16:51:55 -07003557static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003558{
3559 phosphor::logging::log<phosphor::logging::level::INFO>(
3560 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003561 ipmiPrintAndRegister(intel::netFnGeneral,
3562 intel::general::cmdGetChassisIdentifier, NULL,
3563 ipmiOEMGetChassisIdentifier,
3564 PRIVILEGE_USER); // get chassis identifier
3565
3566 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3567 NULL, ipmiOEMSetSystemGUID,
3568 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003569
3570 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003571 registerHandler(prioOemBase, intel::netFnGeneral,
3572 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3573 ipmiOEMDisableBMCSystemReset);
3574
Jason M. Billsb02bf092019-08-15 13:01:56 -07003575 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003576 registerHandler(prioOemBase, intel::netFnGeneral,
3577 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3578 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003579
Vernon Mauery98bbf692019-09-16 11:14:59 -07003580 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3581 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003582
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003583 registerHandler(prioOemBase, intel::netFnGeneral,
3584 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3585 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003586
Vernon Mauery98bbf692019-09-16 11:14:59 -07003587 ipmiPrintAndRegister(intel::netFnGeneral,
3588 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3589 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303590
Vernon Mauery98bbf692019-09-16 11:14:59 -07003591 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3592 intel::general::cmdSendEmbeddedFWUpdStatus,
3593 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303594
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303595 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3596 Privilege::Admin, ipmiOEMSlotIpmb);
3597
Vernon Mauery98bbf692019-09-16 11:14:59 -07003598 ipmiPrintAndRegister(intel::netFnGeneral,
3599 intel::general::cmdSetPowerRestoreDelay, NULL,
3600 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3601
3602 ipmiPrintAndRegister(intel::netFnGeneral,
3603 intel::general::cmdGetPowerRestoreDelay, NULL,
3604 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3605
3606 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3607 intel::general::cmdSetOEMUser2Activation,
3608 Privilege::Callback, ipmiOEMSetUser2Activation);
3609
3610 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3611 intel::general::cmdSetSpecialUserPassword,
3612 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303613
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003614 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003615 registerHandler(prioOemBase, intel::netFnGeneral,
3616 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3617 ipmiOEMGetProcessorErrConfig);
3618
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003619 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003620 registerHandler(prioOemBase, intel::netFnGeneral,
3621 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3622 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003623
Vernon Mauery98bbf692019-09-16 11:14:59 -07003624 ipmiPrintAndRegister(intel::netFnGeneral,
3625 intel::general::cmdSetShutdownPolicy, NULL,
3626 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003627
Vernon Mauery98bbf692019-09-16 11:14:59 -07003628 ipmiPrintAndRegister(intel::netFnGeneral,
3629 intel::general::cmdGetShutdownPolicy, NULL,
3630 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003631
anil kumar appanaf945eee2019-09-25 23:29:11 +00003632 registerHandler(prioOemBase, intel::netFnGeneral,
3633 intel::general::cmdSetFanConfig, Privilege::User,
3634 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003635
Vernon Mauery98bbf692019-09-16 11:14:59 -07003636 registerHandler(prioOemBase, intel::netFnGeneral,
3637 intel::general::cmdGetFanConfig, Privilege::User,
3638 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003639
Vernon Mauery98bbf692019-09-16 11:14:59 -07003640 registerHandler(prioOemBase, intel::netFnGeneral,
3641 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3642 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003643
Vernon Mauery98bbf692019-09-16 11:14:59 -07003644 registerHandler(prioOemBase, intel::netFnGeneral,
3645 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3646 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003647
Vernon Mauery98bbf692019-09-16 11:14:59 -07003648 registerHandler(prioOemBase, intel::netFnGeneral,
3649 intel::general::cmdSetFscParameter, Privilege::User,
3650 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003651
Vernon Mauery98bbf692019-09-16 11:14:59 -07003652 registerHandler(prioOemBase, intel::netFnGeneral,
3653 intel::general::cmdGetFscParameter, Privilege::User,
3654 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303655
Vernon Mauery98bbf692019-09-16 11:14:59 -07003656 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3657 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3658 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003659
Vernon Mauery98bbf692019-09-16 11:14:59 -07003660 registerHandler(prioOemBase, intel::netFnGeneral,
3661 intel::general::cmdGetNmiStatus, Privilege::User,
3662 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003663
Vernon Mauery98bbf692019-09-16 11:14:59 -07003664 registerHandler(prioOemBase, intel::netFnGeneral,
3665 intel::general::cmdSetNmiStatus, Privilege::Operator,
3666 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003667
Vernon Mauery98bbf692019-09-16 11:14:59 -07003668 registerHandler(prioOemBase, intel::netFnGeneral,
3669 intel::general::cmdGetEfiBootOptions, Privilege::User,
3670 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003671
Vernon Mauery98bbf692019-09-16 11:14:59 -07003672 registerHandler(prioOemBase, intel::netFnGeneral,
3673 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3674 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303675
Vernon Mauery98bbf692019-09-16 11:14:59 -07003676 registerHandler(prioOemBase, intel::netFnGeneral,
3677 intel::general::cmdGetSecurityMode, Privilege::User,
3678 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303679
Vernon Mauery98bbf692019-09-16 11:14:59 -07003680 registerHandler(prioOemBase, intel::netFnGeneral,
3681 intel::general::cmdSetSecurityMode, Privilege::Admin,
3682 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003683
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003684 registerHandler(prioOemBase, intel::netFnGeneral,
3685 intel::general::cmdGetLEDStatus, Privilege::Admin,
3686 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003687
Vernon Mauery98bbf692019-09-16 11:14:59 -07003688 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3689 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3690 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3691
3692 registerHandler(prioOemBase, intel::netFnGeneral,
3693 intel::general::cmdSetFaultIndication, Privilege::Operator,
3694 ipmiOEMSetFaultIndication);
3695
3696 registerHandler(prioOemBase, intel::netFnGeneral,
3697 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3698 ipmiOEMSetCRConfig);
3699
3700 registerHandler(prioOemBase, intel::netFnGeneral,
3701 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3702 ipmiOEMGetCRConfig);
3703
3704 registerHandler(prioOemBase, intel::netFnGeneral,
3705 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003706 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003707
Vernon Mauery98bbf692019-09-16 11:14:59 -07003708 registerHandler(prioOemBase, intel::netFnGeneral,
3709 intel::general::cmdSetDimmOffset, Privilege::Operator,
3710 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003711
Vernon Mauery98bbf692019-09-16 11:14:59 -07003712 registerHandler(prioOemBase, intel::netFnGeneral,
3713 intel::general::cmdGetDimmOffset, Privilege::Operator,
3714 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003715
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003716 registerHandler(prioOemBase, intel::netFnGeneral,
3717 intel::general::cmdGetPSUVersion, Privilege::User,
3718 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303719
3720 registerHandler(prioOemBase, intel::netFnGeneral,
3721 intel::general::cmdGetBufferSize, Privilege::User,
3722 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003723}
3724
3725} // namespace ipmi