blob: 9e05308fd376a66468c3af0c35881e4a62e652a7 [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
Jason M. Bills64796042018-10-03 16:51:55 -070017#include "xyz/openbmc_project/Common/error.hpp"
Kuiying Wang45f04982018-12-26 09:23:08 +080018#include "xyz/openbmc_project/Led/Physical/server.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070019
Jia, Chunhuicc49b542019-03-20 15:41:07 +080020#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080021
Chen Yugang7a04f3a2019-10-08 11:12:35 +080022#include <appcommands.hpp>
James Feist91244a62019-02-19 15:04:54 -080023#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080024#include <boost/process/child.hpp>
25#include <boost/process/io.hpp>
Yong Li0669d192019-05-06 14:01:46 +080026#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070027#include <commandutils.hpp>
Zhikui Rence4e73f2019-12-06 13:59:47 -080028#include <gpiod.hpp>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080029#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070030#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070031#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080032#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080033#include <phosphor-logging/log.hpp>
34#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053035#include <sdbusplus/message/types.hpp>
Chen Yugang97cf96e2019-11-01 08:55:11 +080036#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080037#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
38#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080039#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053040#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053041#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080042
James Feistfcd2d3a2020-05-28 10:38:15 -070043#include <array>
44#include <filesystem>
45#include <iostream>
46#include <regex>
47#include <string>
48#include <variant>
49#include <vector>
50
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080051namespace ipmi
52{
Jason M. Bills64796042018-10-03 16:51:55 -070053static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070054
Jason M. Bills64796042018-10-03 16:51:55 -070055static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080056
Suryakanth Sekard509eb92018-11-15 17:44:11 +053057static constexpr auto ethernetIntf =
58 "xyz.openbmc_project.Network.EthernetInterface";
59static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
60static constexpr auto networkService = "xyz.openbmc_project.Network";
61static constexpr auto networkRoot = "/xyz/openbmc_project/network";
62
Chen Yugang97cf96e2019-11-01 08:55:11 +080063static constexpr const char* oemNmiSourceIntf =
64 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080065static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080066 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080067static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
68static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
69
James Feist63efafa2019-07-24 12:39:21 -070070static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
71
Chen Yugang39736d52019-07-12 16:24:33 +080072enum class NmiSource : uint8_t
73{
74 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080075 frontPanelButton = 1,
76 watchdog = 2,
77 chassisCmd = 3,
78 memoryError = 4,
79 pciBusError = 5,
80 pch = 6,
81 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080082};
83
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053084enum class SpecialUserIndex : uint8_t
85{
86 rootUser = 0,
87 atScaleDebugUser = 1
88};
89
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053090static constexpr const char* restricionModeService =
91 "xyz.openbmc_project.RestrictionMode.Manager";
92static constexpr const char* restricionModeBasePath =
93 "/xyz/openbmc_project/control/security/restriction_mode";
94static constexpr const char* restricionModeIntf =
95 "xyz.openbmc_project.Control.Security.RestrictionMode";
96static constexpr const char* restricionModeProperty = "RestrictionMode";
97
98static constexpr const char* specialModeService =
99 "xyz.openbmc_project.SpecialMode";
100static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530101 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530102static constexpr const char* specialModeIntf =
103 "xyz.openbmc_project.Security.SpecialMode";
104static constexpr const char* specialModeProperty = "SpecialMode";
105
106static constexpr const char* dBusPropertyIntf =
107 "org.freedesktop.DBus.Properties";
108static constexpr const char* dBusPropertyGetMethod = "Get";
109static constexpr const char* dBusPropertySetMethod = "Set";
110
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800111// return code: 0 successful
112int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
113{
114 std::string objpath = "/xyz/openbmc_project/FruDevice";
115 std::string intf = "xyz.openbmc_project.FruDeviceManager";
116 std::string service = getService(bus, intf, objpath);
117 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
118 if (valueTree.empty())
119 {
120 phosphor::logging::log<phosphor::logging::level::ERR>(
121 "No object implements interface",
122 phosphor::logging::entry("INTF=%s", intf.c_str()));
123 return -1;
124 }
125
Jason M. Bills64796042018-10-03 16:51:55 -0700126 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800127 {
128 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
129 if (interface == item.second.end())
130 {
131 continue;
132 }
133
134 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
135 if (property == interface->second.end())
136 {
137 continue;
138 }
139
140 try
141 {
142 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700143 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700144 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800145 {
146 phosphor::logging::log<phosphor::logging::level::ERR>(
147 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800148 return -1;
149 }
Jason M. Bills64796042018-10-03 16:51:55 -0700150 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800151 return 0;
152 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700153 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154 {
Jason M. Bills64796042018-10-03 16:51:55 -0700155 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800156 return -1;
157 }
158 }
159 return -1;
160}
Jason M. Bills64796042018-10-03 16:51:55 -0700161
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162// Returns the Chassis Identifier (serial #)
163ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
164 ipmi_request_t request,
165 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700166 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800167 ipmi_context_t context)
168{
169 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700170 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800171 {
Jason M. Bills64796042018-10-03 16:51:55 -0700172 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800173 return IPMI_CC_REQ_DATA_LEN_INVALID;
174 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700175 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
176 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 {
Jason M. Bills64796042018-10-03 16:51:55 -0700178 *dataLen = serial.size(); // length will never exceed response length
179 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800180 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700181 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800182 return IPMI_CC_OK;
183 }
Jason M. Bills64796042018-10-03 16:51:55 -0700184 *dataLen = 0;
185 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800186}
187
188ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
189 ipmi_request_t request,
190 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700191 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192{
193 static constexpr size_t safeBufferLength = 50;
194 char buf[safeBufferLength] = {0};
195 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
196
Jason M. Bills64796042018-10-03 16:51:55 -0700197 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800198 {
Jason M. Bills64796042018-10-03 16:51:55 -0700199 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800200 return IPMI_CC_REQ_DATA_LEN_INVALID;
201 }
202
Jason M. Bills64796042018-10-03 16:51:55 -0700203 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800204
205 snprintf(
206 buf, safeBufferLength,
207 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
208 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
209 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
210 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
211 Data->node3, Data->node2, Data->node1);
212 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
213 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800214
215 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
216 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700217 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
218 std::string service = getService(*dbus, intf, objpath);
219 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800220 return IPMI_CC_OK;
221}
222
Jason M. Billsb02bf092019-08-15 13:01:56 -0700223ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
224 uint7_t reserved1)
225{
226 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
227
228 try
229 {
230 auto service =
231 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
232 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
233 bmcResetDisablesIntf, "ResetOnSMI",
234 !disableResetOnSMI);
235 }
236 catch (std::exception& e)
237 {
238 phosphor::logging::log<phosphor::logging::level::ERR>(
239 "Failed to set BMC reset disables",
240 phosphor::logging::entry("EXCEPTION=%s", e.what()));
241 return ipmi::responseUnspecifiedError();
242 }
243
244 return ipmi::responseSuccess();
245}
246
247ipmi::RspType<bool, // disableResetOnSMI
248 uint7_t // reserved
249 >
250 ipmiOEMGetBMCResetDisables()
251{
252 bool disableResetOnSMI = true;
253
254 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
255 try
256 {
257 auto service =
258 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
259 Value variant =
260 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
261 bmcResetDisablesIntf, "ResetOnSMI");
262 disableResetOnSMI = !std::get<bool>(variant);
263 }
264 catch (std::exception& e)
265 {
266 phosphor::logging::log<phosphor::logging::level::ERR>(
267 "Failed to get BMC reset disables",
268 phosphor::logging::entry("EXCEPTION=%s", e.what()));
269 return ipmi::responseUnspecifiedError();
270 }
271
272 return ipmi::responseSuccess(disableResetOnSMI, 0);
273}
274
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800275ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
276 ipmi_request_t request, ipmi_response_t response,
277 ipmi_data_len_t dataLen, ipmi_context_t context)
278{
279 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
280
Jason M. Bills64796042018-10-03 16:51:55 -0700281 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800282 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800283 *dataLen = 0;
284 return IPMI_CC_REQ_DATA_LEN_INVALID;
285 }
Jason M. Bills64796042018-10-03 16:51:55 -0700286 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800287
Vernon Mauery15419dd2019-05-24 09:40:30 -0700288 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000289 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
290 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800291 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800292 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
293 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700294 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800295 *dataLen = 1;
296 return IPMI_CC_OK;
297}
298
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530299bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
300 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800301{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800302 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530303 std::string bmcVersion;
304 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800305 {
306 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307 }
308
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530309 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800310 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800311 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800312 MetaRevision revision = rev.value();
313 bmcMajor = revision.major;
314
315 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
316 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
317 }
318
319 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530320 std::string meVersion;
321 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800322 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800323 return false;
324 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530325 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
326 constexpr size_t matchedPhosphor = 6;
327 std::smatch results;
328 if (std::regex_match(meVersion, results, pattern1))
329 {
330 if (results.size() == matchedPhosphor)
331 {
332 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
333 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
334 }
335 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800336 return true;
337}
338
339ipmi::RspType<
340 std::variant<std::string,
341 std::tuple<uint8_t, std::array<uint8_t, 2>,
342 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
343 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
344 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530345 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
346 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530347 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800348{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800349 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
350 {
351 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800352 }
353
354 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800355 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800356 {
357 case OEMDevEntityType::biosId:
358 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530359 // Byte 2&3, Only used with selecting BIOS
360 if (!countToRead || !offset)
361 {
362 return ipmi::responseReqDataLenInvalid();
363 }
364
Vernon Mauery15419dd2019-05-24 09:40:30 -0700365 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800366 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000367 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800368 try
369 {
Yong Li2742b852019-12-16 14:55:11 +0800370 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000371 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800372 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700373 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530374 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800375 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800376 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800377 }
Jason M. Bills64796042018-10-03 16:51:55 -0700378 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530379 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700380 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530381 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700382 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800383 else
384 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530385 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800386 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800387
388 std::string readBuf = {0};
389 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530390 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800391 (readBuf.begin()));
392 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800393 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700394 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800395 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800396 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800397 }
398 }
399 break;
400
401 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800402 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530403 // Byte 2&3, Only used with selecting BIOS
404 if (countToRead || offset)
405 {
406 return ipmi::responseReqDataLenInvalid();
407 }
408
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800409 constexpr const size_t verLen = 2;
410 constexpr const size_t verTotalLen = 10;
411 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
412 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
413 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
414 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
415 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
416 // data0/1: BMC version number; data6/7: ME version number
417 // the others: HSC0/1/2 version number, not avaible.
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530418 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800419 {
420 return ipmi::responseUnspecifiedError();
421 }
422 return ipmi::responseSuccess(
423 std::tuple<
424 uint8_t, std::array<uint8_t, verLen>,
425 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
426 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
427 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
428 }
429 break;
430
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800431 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800432 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530433 // Byte 2&3, Only used with selecting BIOS
434 if (countToRead || offset)
435 {
436 return ipmi::responseReqDataLenInvalid();
437 }
438
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800439 constexpr const size_t sdrLen = 2;
440 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
441 return ipmi::responseSuccess(
442 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
443 readBuf});
444 }
445 break;
446
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800447 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800448 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800449 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800450}
451
452ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
453 ipmi_request_t request, ipmi_response_t response,
454 ipmi_data_len_t dataLen, ipmi_context_t context)
455{
456 if (*dataLen != 0)
457 {
Jason M. Bills64796042018-10-03 16:51:55 -0700458 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800459 return IPMI_CC_REQ_DATA_LEN_INVALID;
460 }
461
462 *dataLen = 1;
463 uint8_t* res = reinterpret_cast<uint8_t*>(response);
464 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
465 // AIC is available so that BIOS will not timeout repeatly which leads to
466 // slow booting.
467 *res = 0; // Byte1=Count of SlotPosition/FruID records.
468 return IPMI_CC_OK;
469}
470
Jason M. Bills64796042018-10-03 16:51:55 -0700471ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
472 ipmi_request_t request,
473 ipmi_response_t response,
474 ipmi_data_len_t dataLen,
475 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800476{
Jason M. Bills64796042018-10-03 16:51:55 -0700477 GetPowerRestoreDelayRes* resp =
478 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
479
480 if (*dataLen != 0)
481 {
482 *dataLen = 0;
483 return IPMI_CC_REQ_DATA_LEN_INVALID;
484 }
485
Vernon Mauery15419dd2019-05-24 09:40:30 -0700486 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700487 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700488 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700489 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700490 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700491 powerRestoreDelayIntf, powerRestoreDelayProp);
492
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700493 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700494 resp->byteLSB = delay;
495 resp->byteMSB = delay >> 8;
496
497 *dataLen = sizeof(GetPowerRestoreDelayRes);
498
499 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800500}
501
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800502static uint8_t bcdToDec(uint8_t val)
503{
504 return ((val / 16 * 10) + (val % 16));
505}
506
507// Allows an update utility or system BIOS to send the status of an embedded
508// firmware update attempt to the BMC. After received, BMC will create a logging
509// record.
510ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
511 uint8_t majorRevision,
512 uint8_t minorRevision,
513 uint32_t auxInfo)
514{
515 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700516 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800517 target = (target & selEvtTargetMask) >> selEvtTargetShift;
518
519 /* make sure the status is 0, 1, or 2 as per the spec */
520 if (status > 2)
521 {
522 return ipmi::response(ipmi::ccInvalidFieldRequest);
523 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700524 /* make sure the target is 0, 1, 2, or 4 as per the spec */
525 if (target > 4 || target == 3)
526 {
527 return ipmi::response(ipmi::ccInvalidFieldRequest);
528 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800529 /*orignal OEM command is to record OEM SEL.
530 But openbmc does not support OEM SEL, so we redirect it to redfish event
531 logging. */
532 std::string buildInfo;
533 std::string action;
534 switch (FWUpdateTarget(target))
535 {
536 case FWUpdateTarget::targetBMC:
537 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700538 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800539 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
540 " BuildID: " + std::to_string(auxInfo);
541 buildInfo += std::to_string(auxInfo);
542 break;
543 case FWUpdateTarget::targetBIOS:
544 firmware = "BIOS";
545 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700546 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800547 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
548 " minor: " +
549 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
550 " ReleaseNumber: " + // ASCII encoded
551 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
552 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
553 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
554 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
555 break;
556 case FWUpdateTarget::targetME:
557 firmware = "ME";
558 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700559 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800560 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
561 " minor2: " +
562 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
563 " build1: " +
564 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
565 " build2: " +
566 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
567 break;
568 case FWUpdateTarget::targetOEMEWS:
569 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700570 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800571 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
572 " BuildID: " + std::to_string(auxInfo);
573 break;
574 }
575
Jason M. Billsdc249272019-04-03 09:58:40 -0700576 static const std::string openBMCMessageRegistryVersion("0.1");
577 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
578
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800579 switch (status)
580 {
581 case 0x0:
582 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700583 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800584 break;
585 case 0x1:
586 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700587 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800588 break;
589 case 0x2:
590 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700591 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800592 break;
593 default:
594 action = "unknown";
595 break;
596 }
597
Jason M. Billsdc249272019-04-03 09:58:40 -0700598 std::string firmwareInstanceStr =
599 firmware + " instance: " + std::to_string(instance);
600 std::string message("[firmware update] " + firmwareInstanceStr +
601 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800602
603 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700604 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
605 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
606 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800607 return ipmi::responseSuccess();
608}
609
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530610ipmi::RspType<uint8_t, std::vector<uint8_t>>
611 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
612 uint2_t slotNumber, uint3_t baseBoardSlotNum,
613 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
614 uint8_t netFn, uint8_t cmd,
615 std::optional<std::vector<uint8_t>> writeData)
616{
617 if (reserved1 || reserved2)
618 {
619 return ipmi::responseInvalidFieldRequest();
620 }
621
622 boost::system::error_code ec;
623 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
624 std::vector<uint8_t>>;
625 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
626 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
627 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
628 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
629 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
630 *writeData);
631 if (ec)
632 {
633 phosphor::logging::log<phosphor::logging::level::ERR>(
634 "Failed to call dbus method SlotIpmbRequest");
635 return ipmi::responseUnspecifiedError();
636 }
637
638 std::vector<uint8_t> dataReceived(0);
639 int status = -1;
640 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
641
642 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
643
644 if (status)
645 {
646 phosphor::logging::log<phosphor::logging::level::ERR>(
647 "Failed to get response from SlotIpmbRequest");
648 return ipmi::responseResponseError();
649 }
650 return ipmi::responseSuccess(cc, dataReceived);
651}
652
Jason M. Bills64796042018-10-03 16:51:55 -0700653ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
654 ipmi_request_t request,
655 ipmi_response_t response,
656 ipmi_data_len_t dataLen,
657 ipmi_context_t context)
658{
659 SetPowerRestoreDelayReq* data =
660 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
661 uint16_t delay = 0;
662
663 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
664 {
665 *dataLen = 0;
666 return IPMI_CC_REQ_DATA_LEN_INVALID;
667 }
668 delay = data->byteMSB;
669 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700670 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700671 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700672 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
673 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700674 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
675 *dataLen = 0;
676
677 return IPMI_CC_OK;
678}
679
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700680static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700681{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700682 static constexpr const char* cpuPresencePathPrefix =
683 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
684 static constexpr const char* cpuPresenceIntf =
685 "xyz.openbmc_project.Inventory.Item";
686 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
687 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
688 try
Jason M. Bills64796042018-10-03 16:51:55 -0700689 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700690 auto service =
691 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
692
693 ipmi::Value result = ipmi::getDbusProperty(
694 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
695 return std::get<bool>(result);
696 }
697 catch (const std::exception& e)
698 {
699 phosphor::logging::log<phosphor::logging::level::INFO>(
700 "Cannot find processor presence",
701 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
702 return false;
703 }
704}
705
706ipmi::RspType<bool, // CATERR Reset Enabled
707 bool, // ERR2 Reset Enabled
708 uint6_t, // reserved
709 uint8_t, // reserved, returns 0x3F
710 uint6_t, // CPU1 CATERR Count
711 uint2_t, // CPU1 Status
712 uint6_t, // CPU2 CATERR Count
713 uint2_t, // CPU2 Status
714 uint6_t, // CPU3 CATERR Count
715 uint2_t, // CPU3 Status
716 uint6_t, // CPU4 CATERR Count
717 uint2_t, // CPU4 Status
718 uint8_t // Crashdump Count
719 >
720 ipmiOEMGetProcessorErrConfig()
721{
722 bool resetOnCATERR = false;
723 bool resetOnERR2 = false;
724 uint6_t cpu1CATERRCount = 0;
725 uint6_t cpu2CATERRCount = 0;
726 uint6_t cpu3CATERRCount = 0;
727 uint6_t cpu4CATERRCount = 0;
728 uint8_t crashdumpCount = 0;
729 uint2_t cpu1Status =
730 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
731 uint2_t cpu2Status =
732 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
733 uint2_t cpu3Status =
734 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
735 uint2_t cpu4Status =
736 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
737
738 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
739 try
740 {
741 auto service = ipmi::getService(*busp, processorErrConfigIntf,
742 processorErrConfigObjPath);
743
744 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
745 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
746 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
747 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
748 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
749 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
750 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
751 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
752 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
753 }
754 catch (const std::exception& e)
755 {
756 phosphor::logging::log<phosphor::logging::level::ERR>(
757 "Failed to fetch processor error config",
758 phosphor::logging::entry("ERROR=%s", e.what()));
759 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700760 }
761
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700762 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
763 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
764 cpu2Status, cpu3CATERRCount, cpu3Status,
765 cpu4CATERRCount, cpu4Status, crashdumpCount);
766}
Jason M. Bills64796042018-10-03 16:51:55 -0700767
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700768ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
769 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
770 std::optional<bool> clearCPUErrorCount,
771 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
772{
773 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700774
775 try
776 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700777 auto service = ipmi::getService(*busp, processorErrConfigIntf,
778 processorErrConfigObjPath);
779 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
780 processorErrConfigIntf, "ResetOnCATERR",
781 resetOnCATERR);
782 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
783 processorErrConfigIntf, "ResetOnERR2",
784 resetOnERR2);
785 if (clearCPUErrorCount.value_or(false))
786 {
787 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700788 processorErrConfigIntf, "ErrorCountCPU1",
789 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700790 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700791 processorErrConfigIntf, "ErrorCountCPU2",
792 static_cast<uint8_t>(0));
793 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
794 processorErrConfigIntf, "ErrorCountCPU3",
795 static_cast<uint8_t>(0));
796 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
797 processorErrConfigIntf, "ErrorCountCPU4",
798 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700799 }
800 if (clearCrashdumpCount.value_or(false))
801 {
802 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700803 processorErrConfigIntf, "CrashdumpCount",
804 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700805 }
Jason M. Bills64796042018-10-03 16:51:55 -0700806 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700807 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700808 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800809 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700810 "Failed to set processor error config",
811 phosphor::logging::entry("EXCEPTION=%s", e.what()));
812 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700813 }
814
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700815 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700816}
817
Yong Li703922d2018-11-06 13:25:31 +0800818ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
819 ipmi_request_t request,
820 ipmi_response_t response,
821 ipmi_data_len_t dataLen,
822 ipmi_context_t context)
823{
824 GetOEMShutdownPolicyRes* resp =
825 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
826
827 if (*dataLen != 0)
828 {
829 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800830 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800831 *dataLen = 0;
832 return IPMI_CC_REQ_DATA_LEN_INVALID;
833 }
834
835 *dataLen = 0;
836
837 try
838 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700839 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800840 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700841 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
842 Value variant = getDbusProperty(
843 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
844 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800845
846 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
847 convertPolicyFromString(std::get<std::string>(variant)) ==
848 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
849 NoShutdownOnOCOT)
850 {
851 resp->policy = 0;
852 }
853 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
854 convertPolicyFromString(std::get<std::string>(variant)) ==
855 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
856 Policy::ShutdownOnOCOT)
857 {
858 resp->policy = 1;
859 }
860 else
861 {
862 phosphor::logging::log<phosphor::logging::level::ERR>(
863 "oem_set_shutdown_policy: invalid property!",
864 phosphor::logging::entry(
865 "PROP=%s", std::get<std::string>(variant).c_str()));
866 return IPMI_CC_UNSPECIFIED_ERROR;
867 }
Yong Li703922d2018-11-06 13:25:31 +0800868 // TODO needs to check if it is multi-node products,
869 // policy is only supported on node 3/4
870 resp->policySupport = shutdownPolicySupported;
871 }
872 catch (sdbusplus::exception_t& e)
873 {
874 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
875 return IPMI_CC_UNSPECIFIED_ERROR;
876 }
877
878 *dataLen = sizeof(GetOEMShutdownPolicyRes);
879 return IPMI_CC_OK;
880}
881
882ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
883 ipmi_request_t request,
884 ipmi_response_t response,
885 ipmi_data_len_t dataLen,
886 ipmi_context_t context)
887{
888 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800889 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
890 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
891 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800892
893 // TODO needs to check if it is multi-node products,
894 // policy is only supported on node 3/4
895 if (*dataLen != 1)
896 {
897 phosphor::logging::log<phosphor::logging::level::ERR>(
898 "oem_set_shutdown_policy: invalid input len!");
899 *dataLen = 0;
900 return IPMI_CC_REQ_DATA_LEN_INVALID;
901 }
902
903 *dataLen = 0;
904 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
905 {
906 phosphor::logging::log<phosphor::logging::level::ERR>(
907 "oem_set_shutdown_policy: invalid input!");
908 return IPMI_CC_INVALID_FIELD_REQUEST;
909 }
910
Yong Li0669d192019-05-06 14:01:46 +0800911 if (*req == noShutdownOnOCOT)
912 {
913 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
914 Policy::NoShutdownOnOCOT;
915 }
916 else
917 {
918 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
919 Policy::ShutdownOnOCOT;
920 }
921
Yong Li703922d2018-11-06 13:25:31 +0800922 try
923 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700924 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800925 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700926 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800927 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700928 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800929 oemShutdownPolicyObjPathProp,
930 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800931 }
932 catch (sdbusplus::exception_t& e)
933 {
934 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
935 return IPMI_CC_UNSPECIFIED_ERROR;
936 }
937
938 return IPMI_CC_OK;
939}
940
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530941/** @brief implementation for check the DHCP or not in IPv4
942 * @param[in] Channel - Channel number
943 * @returns true or false.
944 */
945static bool isDHCPEnabled(uint8_t Channel)
946{
947 try
948 {
949 auto ethdevice = getChannelName(Channel);
950 if (ethdevice.empty())
951 {
952 return false;
953 }
954 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700955 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530956 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700957 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
958 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530959 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700960 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530961 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
962 {
963 return true;
964 }
965 else
966 {
967 return false;
968 }
969 }
970 catch (sdbusplus::exception_t& e)
971 {
972 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
973 return true;
974 }
975}
976
977/** @brief implementes for check the DHCP or not in IPv6
978 * @param[in] Channel - Channel number
979 * @returns true or false.
980 */
981static bool isDHCPIPv6Enabled(uint8_t Channel)
982{
983
984 try
985 {
986 auto ethdevice = getChannelName(Channel);
987 if (ethdevice.empty())
988 {
989 return false;
990 }
991 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700992 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530993 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700994 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
995 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530996 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700997 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530998 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
999 {
1000 return true;
1001 }
1002 else
1003 {
1004 return false;
1005 }
1006 }
1007 catch (sdbusplus::exception_t& e)
1008 {
1009 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1010 return true;
1011 }
1012}
1013
1014/** @brief implementes the creating of default new user
1015 * @param[in] userName - new username in 16 bytes.
1016 * @param[in] userPassword - new password in 20 bytes
1017 * @returns ipmi completion code.
1018 */
1019ipmi::RspType<> ipmiOEMSetUser2Activation(
1020 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1021 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1022{
1023 bool userState = false;
1024 // Check for System Interface not exist and LAN should be static
1025 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1026 {
1027 ChannelInfo chInfo;
1028 try
1029 {
1030 getChannelInfo(channel, chInfo);
1031 }
1032 catch (sdbusplus::exception_t& e)
1033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(
1035 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1036 phosphor::logging::entry("MSG: %s", e.description()));
1037 return ipmi::response(ipmi::ccUnspecifiedError);
1038 }
1039 if (chInfo.mediumType ==
1040 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1041 {
1042 phosphor::logging::log<phosphor::logging::level::ERR>(
1043 "ipmiOEMSetUser2Activation: system interface exist .");
1044 return ipmi::response(ipmi::ccCommandNotAvailable);
1045 }
1046 else
1047 {
1048
1049 if (chInfo.mediumType ==
1050 static_cast<uint8_t>(EChannelMediumType::lan8032))
1051 {
1052 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1053 {
1054 phosphor::logging::log<phosphor::logging::level::ERR>(
1055 "ipmiOEMSetUser2Activation: DHCP enabled .");
1056 return ipmi::response(ipmi::ccCommandNotAvailable);
1057 }
1058 }
1059 }
1060 }
1061 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1062 if (ipmi::ccSuccess ==
1063 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1064 {
1065 if (enabledUsers > 1)
1066 {
1067 phosphor::logging::log<phosphor::logging::level::ERR>(
1068 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1069 return ipmi::response(ipmi::ccCommandNotAvailable);
1070 }
1071 // Check the user 2 is enabled or not
1072 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1073 if (userState == true)
1074 {
1075 phosphor::logging::log<phosphor::logging::level::ERR>(
1076 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1077 return ipmi::response(ipmi::ccCommandNotAvailable);
1078 }
1079 }
1080 else
1081 {
1082 return ipmi::response(ipmi::ccUnspecifiedError);
1083 }
1084
1085#if BYTE_ORDER == LITTLE_ENDIAN
1086 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1087#endif
1088#if BYTE_ORDER == BIG_ENDIAN
1089 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1090#endif
1091
Vernon Mauery037cabd2020-05-14 12:16:01 -07001092 // ipmiUserSetUserName correctly handles char*, possibly non-null
1093 // terminated strings using ipmiMaxUserName size
1094 auto userNameRaw = reinterpret_cast<const char*>(userName.data());
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001095
Vernon Mauery037cabd2020-05-14 12:16:01 -07001096 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301097 {
1098 if (ipmi::ccSuccess ==
1099 ipmiUserSetUserPassword(
1100 ipmiDefaultUserId,
1101 reinterpret_cast<const char*>(userPassword.data())))
1102 {
1103 if (ipmi::ccSuccess ==
1104 ipmiUserSetPrivilegeAccess(
1105 ipmiDefaultUserId,
1106 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1107 privAccess, true))
1108 {
1109 phosphor::logging::log<phosphor::logging::level::INFO>(
1110 "ipmiOEMSetUser2Activation: user created successfully ");
1111 return ipmi::responseSuccess();
1112 }
1113 }
1114 // we need to delete the default user id which added in this command as
1115 // password / priv setting is failed.
1116 ipmiUserSetUserName(ipmiDefaultUserId, "");
1117 phosphor::logging::log<phosphor::logging::level::ERR>(
1118 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1119 }
1120 else
1121 {
1122 phosphor::logging::log<phosphor::logging::level::ERR>(
1123 "ipmiOEMSetUser2Activation: Setting username failed.");
1124 }
1125
1126 return ipmi::response(ipmi::ccCommandNotAvailable);
1127}
1128
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301129/** @brief implementes executing the linux command
1130 * @param[in] linux command
1131 * @returns status
1132 */
1133
1134static uint8_t executeCmd(const char* path)
1135{
1136 boost::process::child execProg(path);
1137 execProg.wait();
1138
1139 int retCode = execProg.exit_code();
1140 if (retCode)
1141 {
1142 return ipmi::ccUnspecifiedError;
1143 }
1144 return ipmi::ccSuccess;
1145}
1146
1147/** @brief implementes ASD Security event logging
1148 * @param[in] Event message string
1149 * @param[in] Event Severity
1150 * @returns status
1151 */
1152
1153static void atScaleDebugEventlog(std::string msg, int severity)
1154{
1155 std::string eventStr = "OpenBMC.0.1." + msg;
1156 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1157 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1158 eventStr.c_str(), NULL);
1159}
1160
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301161/** @brief implementes setting password for special user
1162 * @param[in] specialUserIndex
1163 * @param[in] userPassword - new password in 20 bytes
1164 * @returns ipmi completion code.
1165 */
1166ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1167 uint8_t specialUserIndex,
1168 std::vector<uint8_t> userPassword)
1169{
1170 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301171 ipmi_ret_t status = ipmi::ccSuccess;
1172
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301173 try
1174 {
1175 getChannelInfo(ctx->channel, chInfo);
1176 }
1177 catch (sdbusplus::exception_t& e)
1178 {
1179 phosphor::logging::log<phosphor::logging::level::ERR>(
1180 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1181 phosphor::logging::entry("MSG: %s", e.description()));
1182 return ipmi::responseUnspecifiedError();
1183 }
1184 if (chInfo.mediumType !=
1185 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1186 {
1187 phosphor::logging::log<phosphor::logging::level::ERR>(
1188 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1189 "interface");
1190 return ipmi::responseCommandNotAvailable();
1191 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301192
1193 // 0 for root user and 1 for AtScaleDebug is allowed
1194 if (specialUserIndex >
1195 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301196 {
1197 phosphor::logging::log<phosphor::logging::level::ERR>(
1198 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1199 return ipmi::responseParmOutOfRange();
1200 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301201 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301202 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301203 constexpr uint8_t minPasswordSizeRequired = 6;
1204 std::string passwd;
1205 if (userPassword.size() < minPasswordSizeRequired ||
1206 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1207 {
1208 return ipmi::responseReqDataLenInvalid();
1209 }
1210 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1211 userPassword.size());
1212 if (specialUserIndex ==
1213 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1214 {
1215 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1216
1217 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1218 }
1219 else
1220 {
1221 status = ipmiSetSpecialUserPassword("root", passwd);
1222 }
1223 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301224 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301225 else
1226 {
1227 if (specialUserIndex ==
1228 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1229 {
1230 status = executeCmd("passwd -d root");
1231 }
1232 else
1233 {
1234
1235 status = executeCmd("passwd -d asdbg");
1236
1237 if (status == 0)
1238 {
1239 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1240 LOG_INFO);
1241 }
1242 }
1243 return ipmi::response(status);
1244 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301245}
1246
Kuiying Wang45f04982018-12-26 09:23:08 +08001247namespace ledAction
1248{
1249using namespace sdbusplus::xyz::openbmc_project::Led::server;
1250std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001251 {Physical::Action::Off, 0},
1252 {Physical::Action::On, 2},
1253 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001254
1255std::map<uint8_t, std::string> offsetObjPath = {
1256 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1257
1258} // namespace ledAction
1259
1260int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1261 const std::string& objPath, uint8_t& state)
1262{
1263 try
1264 {
1265 std::string service = getService(bus, intf, objPath);
1266 Value stateValue =
1267 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001268 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001269 state = ledAction::actionDbusToIpmi.at(
1270 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1271 convertActionFromString(strState));
1272 }
1273 catch (sdbusplus::exception::SdBusError& e)
1274 {
1275 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1276 return -1;
1277 }
1278 return 0;
1279}
1280
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001281ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001282{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001283 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001284 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001285 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001286 for (auto it = ledAction::offsetObjPath.begin();
1287 it != ledAction::offsetObjPath.end(); ++it)
1288 {
1289 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001290 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001291 {
1292 phosphor::logging::log<phosphor::logging::level::ERR>(
1293 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001294 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001295 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001296 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001297 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001298 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001299}
1300
Yong Li23737fe2019-02-19 08:49:55 +08001301ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1302 ipmi_request_t request,
1303 ipmi_response_t response,
1304 ipmi_data_len_t dataLen,
1305 ipmi_context_t context)
1306{
1307 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1308 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1309
1310 if (*dataLen == 0)
1311 {
1312 phosphor::logging::log<phosphor::logging::level::ERR>(
1313 "CfgHostSerial: invalid input len!",
1314 phosphor::logging::entry("LEN=%d", *dataLen));
1315 return IPMI_CC_REQ_DATA_LEN_INVALID;
1316 }
1317
1318 switch (req->command)
1319 {
1320 case getHostSerialCfgCmd:
1321 {
1322 if (*dataLen != 1)
1323 {
1324 phosphor::logging::log<phosphor::logging::level::ERR>(
1325 "CfgHostSerial: invalid input len!");
1326 *dataLen = 0;
1327 return IPMI_CC_REQ_DATA_LEN_INVALID;
1328 }
1329
1330 *dataLen = 0;
1331
1332 boost::process::ipstream is;
1333 std::vector<std::string> data;
1334 std::string line;
1335 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1336 boost::process::std_out > is);
1337
1338 while (c1.running() && std::getline(is, line) && !line.empty())
1339 {
1340 data.push_back(line);
1341 }
1342
1343 c1.wait();
1344 if (c1.exit_code())
1345 {
1346 phosphor::logging::log<phosphor::logging::level::ERR>(
1347 "CfgHostSerial:: error on execute",
1348 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1349 // Using the default value
1350 *resp = 0;
1351 }
1352 else
1353 {
1354 if (data.size() != 1)
1355 {
1356 phosphor::logging::log<phosphor::logging::level::ERR>(
1357 "CfgHostSerial:: error on read env");
1358 return IPMI_CC_UNSPECIFIED_ERROR;
1359 }
1360 try
1361 {
1362 unsigned long tmp = std::stoul(data[0]);
1363 if (tmp > std::numeric_limits<uint8_t>::max())
1364 {
1365 throw std::out_of_range("Out of range");
1366 }
1367 *resp = static_cast<uint8_t>(tmp);
1368 }
1369 catch (const std::invalid_argument& e)
1370 {
1371 phosphor::logging::log<phosphor::logging::level::ERR>(
1372 "invalid config ",
1373 phosphor::logging::entry("ERR=%s", e.what()));
1374 return IPMI_CC_UNSPECIFIED_ERROR;
1375 }
1376 catch (const std::out_of_range& e)
1377 {
1378 phosphor::logging::log<phosphor::logging::level::ERR>(
1379 "out_of_range config ",
1380 phosphor::logging::entry("ERR=%s", e.what()));
1381 return IPMI_CC_UNSPECIFIED_ERROR;
1382 }
1383 }
1384
1385 *dataLen = 1;
1386 break;
1387 }
1388 case setHostSerialCfgCmd:
1389 {
1390 if (*dataLen != sizeof(CfgHostSerialReq))
1391 {
1392 phosphor::logging::log<phosphor::logging::level::ERR>(
1393 "CfgHostSerial: invalid input len!");
1394 *dataLen = 0;
1395 return IPMI_CC_REQ_DATA_LEN_INVALID;
1396 }
1397
1398 *dataLen = 0;
1399
1400 if (req->parameter > HostSerialCfgParamMax)
1401 {
1402 phosphor::logging::log<phosphor::logging::level::ERR>(
1403 "CfgHostSerial: invalid input!");
1404 return IPMI_CC_INVALID_FIELD_REQUEST;
1405 }
1406
1407 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1408 std::to_string(req->parameter));
1409
1410 c1.wait();
1411 if (c1.exit_code())
1412 {
1413 phosphor::logging::log<phosphor::logging::level::ERR>(
1414 "CfgHostSerial:: error on execute",
1415 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1416 return IPMI_CC_UNSPECIFIED_ERROR;
1417 }
1418 break;
1419 }
1420 default:
1421 phosphor::logging::log<phosphor::logging::level::ERR>(
1422 "CfgHostSerial: invalid input!");
1423 *dataLen = 0;
1424 return IPMI_CC_INVALID_FIELD_REQUEST;
1425 }
1426
1427 return IPMI_CC_OK;
1428}
1429
James Feist91244a62019-02-19 15:04:54 -08001430constexpr const char* thermalModeInterface =
1431 "xyz.openbmc_project.Control.ThermalMode";
1432constexpr const char* thermalModePath =
1433 "/xyz/openbmc_project/control/thermal_mode";
1434
1435bool getFanProfileInterface(
1436 sdbusplus::bus::bus& bus,
1437 boost::container::flat_map<
1438 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1439{
1440 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1441 "GetAll");
1442 call.append(thermalModeInterface);
1443 try
1444 {
1445 auto data = bus.call(call);
1446 data.read(resp);
1447 }
1448 catch (sdbusplus::exception_t& e)
1449 {
1450 phosphor::logging::log<phosphor::logging::level::ERR>(
1451 "getFanProfileInterface: can't get thermal mode!",
1452 phosphor::logging::entry("ERR=%s", e.what()));
1453 return false;
1454 }
1455 return true;
1456}
1457
anil kumar appanaf945eee2019-09-25 23:29:11 +00001458/**@brief implements the OEM set fan config.
1459 * @param selectedFanProfile - fan profile to enable
1460 * @param reserved1
1461 * @param performanceMode - Performance/Acoustic mode
1462 * @param reserved2
1463 * @param setPerformanceMode - set Performance/Acoustic mode
1464 * @param setFanProfile - set fan profile
1465 *
1466 * @return IPMI completion code.
1467 **/
1468ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1469
1470 uint2_t reserved1, bool performanceMode,
1471 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301472 bool setFanProfile,
1473 std::optional<uint8_t> dimmGroupId,
1474 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001475{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001476 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001477 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001478 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001479 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301480
1481 if (dimmGroupId)
1482 {
1483 if (*dimmGroupId >= maxCPUNum)
1484 {
1485 return ipmi::responseInvalidFieldRequest();
1486 }
1487 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1488 {
1489 return ipmi::responseInvalidFieldRequest();
1490 }
1491 }
1492
James Feist91244a62019-02-19 15:04:54 -08001493 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001494 boost::container::flat_map<
1495 std::string, std::variant<std::vector<std::string>, std::string>>
1496 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001497 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1498 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001499 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001500 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001501 }
1502
1503 std::vector<std::string>* supported =
1504 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1505 if (supported == nullptr)
1506 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001507 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001508 }
1509 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001510 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001511 {
James Feist91244a62019-02-19 15:04:54 -08001512 if (performanceMode)
1513 {
1514
1515 if (std::find(supported->begin(), supported->end(),
1516 "Performance") != supported->end())
1517 {
1518 mode = "Performance";
1519 }
1520 }
1521 else
1522 {
James Feist91244a62019-02-19 15:04:54 -08001523 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1524 supported->end())
1525 {
1526 mode = "Acoustic";
1527 }
1528 }
1529 if (mode.empty())
1530 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001531 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001532 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001533
1534 try
1535 {
1536 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1537 thermalModeInterface, "Current", mode);
1538 }
1539 catch (sdbusplus::exception_t& e)
1540 {
1541 phosphor::logging::log<phosphor::logging::level::ERR>(
1542 "ipmiOEMSetFanConfig: can't set thermal mode!",
1543 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1544 return ipmi::responseResponseError();
1545 }
James Feist91244a62019-02-19 15:04:54 -08001546 }
1547
anil kumar appanaf945eee2019-09-25 23:29:11 +00001548 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001549}
1550
James Feist5b693632019-07-09 09:06:09 -07001551ipmi::RspType<uint8_t, // profile support map
1552 uint8_t, // fan control profile enable
1553 uint8_t, // flags
1554 uint32_t // dimm presence bit map
1555 >
1556 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001557{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301558 if (dimmGroupId >= maxCPUNum)
1559 {
1560 return ipmi::responseInvalidFieldRequest();
1561 }
1562
1563 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1564
1565 if (!cpuStatus)
1566 {
1567 return ipmi::responseInvalidFieldRequest();
1568 }
1569
James Feist91244a62019-02-19 15:04:54 -08001570 boost::container::flat_map<
1571 std::string, std::variant<std::vector<std::string>, std::string>>
1572 profileData;
1573
Vernon Mauery15419dd2019-05-24 09:40:30 -07001574 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1575 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001576 {
James Feist5b693632019-07-09 09:06:09 -07001577 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001578 }
1579
1580 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1581
1582 if (current == nullptr)
1583 {
1584 phosphor::logging::log<phosphor::logging::level::ERR>(
1585 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001586 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001587 }
1588 bool performance = (*current == "Performance");
1589
James Feist5b693632019-07-09 09:06:09 -07001590 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001591 if (performance)
1592 {
James Feist5b693632019-07-09 09:06:09 -07001593 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001594 }
1595
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001596 constexpr uint8_t fanControlDefaultProfile = 0x80;
1597 constexpr uint8_t fanControlProfileState = 0x00;
1598 constexpr uint32_t dimmPresenceBitmap = 0x00;
1599
1600 return ipmi::responseSuccess(fanControlDefaultProfile,
1601 fanControlProfileState, flags,
1602 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001603}
James Feist5f957ca2019-03-14 15:33:55 -07001604constexpr const char* cfmLimitSettingPath =
1605 "/xyz/openbmc_project/control/cfm_limit";
1606constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001607constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001608constexpr const size_t legacyPCHSensorNumber = 0x22;
1609constexpr const char* exitAirPathName = "Exit_Air";
1610constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001611constexpr const char* pidConfigurationIface =
1612 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001613
James Feist09f6b602019-08-08 11:30:03 -07001614static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001615{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001616 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001617 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001618 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1619 "/xyz/openbmc_project/object_mapper",
1620 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001621
James Feistacc8a4e2019-04-02 14:23:57 -07001622 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001623 std::string path;
1624 GetSubTreeType resp;
1625 try
1626 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001627 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001628 reply.read(resp);
1629 }
1630 catch (sdbusplus::exception_t&)
1631 {
1632 phosphor::logging::log<phosphor::logging::level::ERR>(
1633 "ipmiOEMGetFscParameter: mapper error");
1634 };
James Feist09f6b602019-08-08 11:30:03 -07001635 auto config =
1636 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1637 return pair.first.find(name) != std::string::npos;
1638 });
James Feistfaa4f222019-03-21 16:21:55 -07001639 if (config != resp.end())
1640 {
1641 path = std::move(config->first);
1642 }
1643 return path;
1644}
James Feist5f957ca2019-03-14 15:33:55 -07001645
James Feistacc8a4e2019-04-02 14:23:57 -07001646// flat map to make alphabetical
1647static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1648{
1649 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001650 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001651 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001652 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1653 "/xyz/openbmc_project/object_mapper",
1654 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001655
1656 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1657 GetSubTreeType resp;
1658
1659 try
1660 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001661 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001662 reply.read(resp);
1663 }
1664 catch (sdbusplus::exception_t&)
1665 {
1666 phosphor::logging::log<phosphor::logging::level::ERR>(
1667 "getFanConfigPaths: mapper error");
1668 };
1669 for (const auto& [path, objects] : resp)
1670 {
1671 if (objects.empty())
1672 {
1673 continue; // should be impossible
1674 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001675
1676 try
1677 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001678 ret.emplace(path,
1679 getAllDbusProperties(*dbus, objects[0].first, path,
1680 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001681 }
1682 catch (sdbusplus::exception_t& e)
1683 {
1684 phosphor::logging::log<phosphor::logging::level::ERR>(
1685 "getPidConfigs: can't get DbusProperties!",
1686 phosphor::logging::entry("ERR=%s", e.what()));
1687 }
James Feistacc8a4e2019-04-02 14:23:57 -07001688 }
1689 return ret;
1690}
1691
1692ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1693{
1694 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1695 if (data.empty())
1696 {
1697 return ipmi::responseResponseError();
1698 }
1699 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1700 for (const auto& [_, pid] : data)
1701 {
1702 auto findClass = pid.find("Class");
1703 if (findClass == pid.end())
1704 {
1705 phosphor::logging::log<phosphor::logging::level::ERR>(
1706 "ipmiOEMGetFscParameter: found illegal pid "
1707 "configurations");
1708 return ipmi::responseResponseError();
1709 }
1710 std::string type = std::get<std::string>(findClass->second);
1711 if (type == "fan")
1712 {
1713 auto findOutLimit = pid.find("OutLimitMin");
1714 if (findOutLimit == pid.end())
1715 {
1716 phosphor::logging::log<phosphor::logging::level::ERR>(
1717 "ipmiOEMGetFscParameter: found illegal pid "
1718 "configurations");
1719 return ipmi::responseResponseError();
1720 }
1721 // get the min out of all the offsets
1722 minOffset = std::min(
1723 minOffset,
1724 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1725 }
1726 }
1727 if (minOffset == std::numeric_limits<uint8_t>::max())
1728 {
1729 phosphor::logging::log<phosphor::logging::level::ERR>(
1730 "ipmiOEMGetFscParameter: found no fan configurations!");
1731 return ipmi::responseResponseError();
1732 }
1733
1734 return ipmi::responseSuccess(minOffset);
1735}
1736
1737ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1738{
1739 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1740 if (data.empty())
1741 {
1742
1743 phosphor::logging::log<phosphor::logging::level::ERR>(
1744 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1745 return ipmi::responseResponseError();
1746 }
1747
Vernon Mauery15419dd2019-05-24 09:40:30 -07001748 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001749 bool found = false;
1750 for (const auto& [path, pid] : data)
1751 {
1752 auto findClass = pid.find("Class");
1753 if (findClass == pid.end())
1754 {
1755
1756 phosphor::logging::log<phosphor::logging::level::ERR>(
1757 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1758 "configurations");
1759 return ipmi::responseResponseError();
1760 }
1761 std::string type = std::get<std::string>(findClass->second);
1762 if (type == "fan")
1763 {
1764 auto findOutLimit = pid.find("OutLimitMin");
1765 if (findOutLimit == pid.end())
1766 {
1767
1768 phosphor::logging::log<phosphor::logging::level::ERR>(
1769 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1770 "configurations");
1771 return ipmi::responseResponseError();
1772 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001773 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001774 path, pidConfigurationIface, "OutLimitMin",
1775 static_cast<double>(offset));
1776 found = true;
1777 }
1778 }
1779 if (!found)
1780 {
1781 phosphor::logging::log<phosphor::logging::level::ERR>(
1782 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1783 return ipmi::responseResponseError();
1784 }
1785
1786 return ipmi::responseSuccess();
1787}
1788
1789ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1790 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001791{
1792 constexpr const size_t disableLimiting = 0x0;
1793
Vernon Mauery15419dd2019-05-24 09:40:30 -07001794 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001795 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001796 {
James Feist09f6b602019-08-08 11:30:03 -07001797 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001798 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001799 {
James Feist09f6b602019-08-08 11:30:03 -07001800 pathName = exitAirPathName;
1801 }
1802 else if (param1 == legacyPCHSensorNumber)
1803 {
1804 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001805 }
1806 else
1807 {
James Feistacc8a4e2019-04-02 14:23:57 -07001808 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001809 }
James Feist09f6b602019-08-08 11:30:03 -07001810 std::string path = getConfigPath(pathName);
1811 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1812 pidConfigurationIface, "SetPoint",
1813 static_cast<double>(param2));
1814 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001815 }
James Feistacc8a4e2019-04-02 14:23:57 -07001816 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001817 {
James Feistacc8a4e2019-04-02 14:23:57 -07001818 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001819
1820 // must be greater than 50 based on eps
1821 if (cfm < 50 && cfm != disableLimiting)
1822 {
James Feistacc8a4e2019-04-02 14:23:57 -07001823 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001824 }
1825
1826 try
1827 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001828 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001829 cfmLimitIface, "Limit",
1830 static_cast<double>(cfm));
1831 }
1832 catch (sdbusplus::exception_t& e)
1833 {
1834 phosphor::logging::log<phosphor::logging::level::ERR>(
1835 "ipmiOEMSetFscParameter: can't set cfm setting!",
1836 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001837 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001838 }
James Feistacc8a4e2019-04-02 14:23:57 -07001839 return ipmi::responseSuccess();
1840 }
1841 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1842 {
1843 constexpr const size_t maxDomainCount = 8;
1844 uint8_t requestedDomainMask = param1;
1845 boost::container::flat_map data = getPidConfigs();
1846 if (data.empty())
1847 {
1848
1849 phosphor::logging::log<phosphor::logging::level::ERR>(
1850 "ipmiOEMSetFscParameter: found no pid configurations!");
1851 return ipmi::responseResponseError();
1852 }
1853 size_t count = 0;
1854 for (const auto& [path, pid] : data)
1855 {
1856 auto findClass = pid.find("Class");
1857 if (findClass == pid.end())
1858 {
1859
1860 phosphor::logging::log<phosphor::logging::level::ERR>(
1861 "ipmiOEMSetFscParameter: found illegal pid "
1862 "configurations");
1863 return ipmi::responseResponseError();
1864 }
1865 std::string type = std::get<std::string>(findClass->second);
1866 if (type == "fan")
1867 {
1868 if (requestedDomainMask & (1 << count))
1869 {
1870 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001871 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001872 pidConfigurationIface, "OutLimitMax",
1873 static_cast<double>(param2));
1874 }
1875 count++;
1876 }
1877 }
1878 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001879 }
1880 else
1881 {
1882 // todo other command parts possibly
1883 // tcontrol is handled in peci now
1884 // fan speed offset not implemented yet
1885 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001886 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001887 }
1888}
1889
James Feistacc8a4e2019-04-02 14:23:57 -07001890ipmi::RspType<
1891 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1892 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001893{
James Feist09f6b602019-08-08 11:30:03 -07001894 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001895
Vernon Mauery15419dd2019-05-24 09:40:30 -07001896 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001897 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001898 {
James Feistacc8a4e2019-04-02 14:23:57 -07001899 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001900 {
James Feistacc8a4e2019-04-02 14:23:57 -07001901 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001902 }
1903
James Feist09f6b602019-08-08 11:30:03 -07001904 std::string pathName;
1905
1906 if (*param == legacyExitAirSensorNumber)
1907 {
1908 pathName = exitAirPathName;
1909 }
1910 else if (*param == legacyPCHSensorNumber)
1911 {
1912 pathName = pchPathName;
1913 }
1914 else
James Feistfaa4f222019-03-21 16:21:55 -07001915 {
James Feistacc8a4e2019-04-02 14:23:57 -07001916 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001917 }
James Feist09f6b602019-08-08 11:30:03 -07001918
1919 uint8_t setpoint = legacyDefaultSetpoint;
1920 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001921 if (path.size())
1922 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001923 Value val = ipmi::getDbusProperty(
1924 *dbus, "xyz.openbmc_project.EntityManager", path,
1925 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001926 setpoint = std::floor(std::get<double>(val) + 0.5);
1927 }
1928
1929 // old implementation used to return the "default" and current, we
1930 // don't make the default readily available so just make both the
1931 // same
James Feistfaa4f222019-03-21 16:21:55 -07001932
James Feistacc8a4e2019-04-02 14:23:57 -07001933 return ipmi::responseSuccess(
1934 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001935 }
James Feistacc8a4e2019-04-02 14:23:57 -07001936 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1937 {
1938 constexpr const size_t maxDomainCount = 8;
1939
1940 if (!param)
1941 {
1942 return ipmi::responseReqDataLenInvalid();
1943 }
1944 uint8_t requestedDomain = *param;
1945 if (requestedDomain >= maxDomainCount)
1946 {
1947 return ipmi::responseInvalidFieldRequest();
1948 }
1949
1950 boost::container::flat_map data = getPidConfigs();
1951 if (data.empty())
1952 {
1953 phosphor::logging::log<phosphor::logging::level::ERR>(
1954 "ipmiOEMGetFscParameter: found no pid configurations!");
1955 return ipmi::responseResponseError();
1956 }
1957 size_t count = 0;
1958 for (const auto& [_, pid] : data)
1959 {
1960 auto findClass = pid.find("Class");
1961 if (findClass == pid.end())
1962 {
1963 phosphor::logging::log<phosphor::logging::level::ERR>(
1964 "ipmiOEMGetFscParameter: found illegal pid "
1965 "configurations");
1966 return ipmi::responseResponseError();
1967 }
1968 std::string type = std::get<std::string>(findClass->second);
1969 if (type == "fan")
1970 {
1971 if (requestedDomain == count)
1972 {
1973 auto findOutLimit = pid.find("OutLimitMax");
1974 if (findOutLimit == pid.end())
1975 {
1976 phosphor::logging::log<phosphor::logging::level::ERR>(
1977 "ipmiOEMGetFscParameter: found illegal pid "
1978 "configurations");
1979 return ipmi::responseResponseError();
1980 }
1981
1982 return ipmi::responseSuccess(
1983 static_cast<uint8_t>(std::floor(
1984 std::get<double>(findOutLimit->second) + 0.5)));
1985 }
1986 else
1987 {
1988 count++;
1989 }
1990 }
1991 }
1992
1993 return ipmi::responseInvalidFieldRequest();
1994 }
1995 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001996 {
1997
1998 /*
1999 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002000 previous behavior didn't seem to prevent this, ignore the check for
2001 now.
James Feist5f957ca2019-03-14 15:33:55 -07002002
James Feistacc8a4e2019-04-02 14:23:57 -07002003 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002004 {
2005 phosphor::logging::log<phosphor::logging::level::ERR>(
2006 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002007 return IPMI_CC_REQ_DATA_LEN_INVALID;
2008 }
2009 */
2010 Value cfmLimit;
2011 Value cfmMaximum;
2012 try
2013 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002014 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002015 cfmLimitSettingPath, cfmLimitIface,
2016 "Limit");
2017 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002018 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002019 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2020 }
2021 catch (sdbusplus::exception_t& e)
2022 {
2023 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002024 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002025 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002026 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002027 }
2028
James Feistacc8a4e2019-04-02 14:23:57 -07002029 double cfmMax = std::get<double>(cfmMaximum);
2030 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002031
James Feistacc8a4e2019-04-02 14:23:57 -07002032 cfmLim = std::floor(cfmLim + 0.5);
2033 cfmMax = std::floor(cfmMax + 0.5);
2034 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2035 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002036
James Feistacc8a4e2019-04-02 14:23:57 -07002037 return ipmi::responseSuccess(
2038 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002039 }
James Feistacc8a4e2019-04-02 14:23:57 -07002040
James Feist5f957ca2019-03-14 15:33:55 -07002041 else
2042 {
2043 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002044 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002045 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002046 }
2047}
2048
Cheng C Yang773703a2019-08-15 09:41:11 +08002049using crConfigVariant =
2050 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2051
2052int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2053 const crConfigVariant& value,
2054 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2055{
2056 boost::system::error_code ec;
2057 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002058 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002059 "/xyz/openbmc_project/control/power_supply_redundancy",
2060 "org.freedesktop.DBus.Properties", "Set",
2061 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2062 if (ec)
2063 {
2064 phosphor::logging::log<phosphor::logging::level::ERR>(
2065 "Failed to set dbus property to cold redundancy");
2066 return -1;
2067 }
2068
2069 return 0;
2070}
2071
2072int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2073 crConfigVariant& value,
Yong Li19445ab2019-12-20 18:25:29 +08002074 const std::string& service = "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002075 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2076{
2077 boost::system::error_code ec;
2078 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002079 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002080 "/xyz/openbmc_project/control/power_supply_redundancy",
2081 "org.freedesktop.DBus.Properties", "Get",
2082 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2083 if (ec)
2084 {
2085 phosphor::logging::log<phosphor::logging::level::ERR>(
2086 "Failed to get dbus property to cold redundancy");
2087 return -1;
2088 }
2089 return 0;
2090}
2091
2092uint8_t getPSUCount(void)
2093{
2094 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2095 ipmi::Value num;
2096 try
2097 {
2098 num = ipmi::getDbusProperty(
2099 *dbus, "xyz.openbmc_project.PSURedundancy",
2100 "/xyz/openbmc_project/control/power_supply_redundancy",
2101 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2102 }
2103 catch (sdbusplus::exception_t& e)
2104 {
2105 phosphor::logging::log<phosphor::logging::level::ERR>(
2106 "Failed to get PSUNumber property from dbus interface");
2107 return 0;
2108 }
2109 uint8_t* pNum = std::get_if<uint8_t>(&num);
2110 if (!pNum)
2111 {
2112 phosphor::logging::log<phosphor::logging::level::ERR>(
2113 "Error to get PSU Number");
2114 return 0;
2115 }
2116 return *pNum;
2117}
2118
2119bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2120{
2121 if (conf.size() < num)
2122 {
2123 phosphor::logging::log<phosphor::logging::level::ERR>(
2124 "Invalid PSU Ranking");
2125 return false;
2126 }
2127 std::set<uint8_t> confSet;
2128 for (uint8_t i = 0; i < num; i++)
2129 {
2130 if (conf[i] > num)
2131 {
2132 phosphor::logging::log<phosphor::logging::level::ERR>(
2133 "PSU Ranking is larger than current PSU number");
2134 return false;
2135 }
2136 confSet.emplace(conf[i]);
2137 }
2138
2139 if (confSet.size() != num)
2140 {
2141 phosphor::logging::log<phosphor::logging::level::ERR>(
2142 "duplicate PSU Ranking");
2143 return false;
2144 }
2145 return true;
2146}
2147
2148enum class crParameter
2149{
2150 crStatus = 0,
2151 crFeature = 1,
2152 rotationFeature = 2,
2153 rotationAlgo = 3,
2154 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002155 numOfPSU = 5,
2156 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002157};
2158
2159constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2160static const constexpr uint32_t oneDay = 0x15180;
2161static const constexpr uint32_t oneMonth = 0xf53700;
2162static const constexpr uint8_t userSpecific = 0x01;
2163static const constexpr uint8_t crSetCompleted = 0;
2164ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2165 uint8_t parameter,
2166 ipmi::message::Payload& payload)
2167{
2168 switch (static_cast<crParameter>(parameter))
2169 {
2170 case crParameter::crFeature:
2171 {
2172 uint8_t param1;
2173 if (payload.unpack(param1) || !payload.fullyUnpacked())
2174 {
2175 return ipmi::responseReqDataLenInvalid();
2176 }
2177 // ColdRedundancy Enable can only be true or flase
2178 if (param1 > 1)
2179 {
2180 return ipmi::responseInvalidFieldRequest();
2181 }
2182 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2183 static_cast<bool>(param1)))
2184 {
2185 return ipmi::responseResponseError();
2186 }
2187 break;
2188 }
2189 case crParameter::rotationFeature:
2190 {
2191 uint8_t param1;
2192 if (payload.unpack(param1) || !payload.fullyUnpacked())
2193 {
2194 return ipmi::responseReqDataLenInvalid();
2195 }
2196 // Rotation Enable can only be true or false
2197 if (param1 > 1)
2198 {
2199 return ipmi::responseInvalidFieldRequest();
2200 }
2201 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2202 {
2203 return ipmi::responseResponseError();
2204 }
2205 break;
2206 }
2207 case crParameter::rotationAlgo:
2208 {
2209 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2210 std::string algoName;
2211 uint8_t param1;
2212 if (payload.unpack(param1))
2213 {
2214 return ipmi::responseReqDataLenInvalid();
2215 }
2216 switch (param1)
2217 {
2218 case 0:
2219 algoName = "xyz.openbmc_project.Control."
2220 "PowerSupplyRedundancy.Algo.bmcSpecific";
2221 break;
2222 case 1:
2223 algoName = "xyz.openbmc_project.Control."
2224 "PowerSupplyRedundancy.Algo.userSpecific";
2225 break;
2226 default:
2227 return ipmi::responseInvalidFieldRequest();
2228 }
2229 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2230 {
2231 return ipmi::responseResponseError();
2232 }
2233
2234 uint8_t numberOfPSU = getPSUCount();
2235 if (!numberOfPSU)
2236 {
2237 return ipmi::responseResponseError();
2238 }
2239 std::vector<uint8_t> rankOrder;
2240
2241 if (param1 == userSpecific)
2242 {
2243 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2244 {
2245 ipmi::responseReqDataLenInvalid();
2246 }
Yong Li83315132019-10-23 17:42:24 +08002247 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002248 {
2249 return ipmi::responseReqDataLenInvalid();
2250 }
2251
2252 if (!validateCRAlgo(rankOrder, numberOfPSU))
2253 {
2254 return ipmi::responseInvalidFieldRequest();
2255 }
2256 }
2257 else
2258 {
2259 if (rankOrder.size() > 0)
2260 {
2261 return ipmi::responseReqDataLenInvalid();
2262 }
2263 for (uint8_t i = 1; i <= numberOfPSU; i++)
2264 {
2265 rankOrder.emplace_back(i);
2266 }
2267 }
2268 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2269 {
2270 return ipmi::responseResponseError();
2271 }
2272 break;
2273 }
2274 case crParameter::rotationPeriod:
2275 {
2276 // Minimum Rotation period is One day (86400 seconds) and Max
2277 // Rotation Period is 6 month (0xf53700 seconds)
2278 uint32_t period;
2279 if (payload.unpack(period) || !payload.fullyUnpacked())
2280 {
2281 return ipmi::responseReqDataLenInvalid();
2282 }
2283 if ((period < oneDay) || (period > oneMonth))
2284 {
2285 return ipmi::responseInvalidFieldRequest();
2286 }
2287 if (setCRConfig(ctx, "PeriodOfRotation", period))
2288 {
2289 return ipmi::responseResponseError();
2290 }
2291 break;
2292 }
2293 default:
2294 {
2295 return ipmi::response(ccParameterNotSupported);
2296 }
2297 }
2298
2299 // TODO Halfwidth needs to set SetInProgress
2300 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002301 std::string("xyz.openbmc_project.Control."
2302 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002303 {
2304 return ipmi::responseResponseError();
2305 }
2306 return ipmi::responseSuccess(crSetCompleted);
2307}
2308
Yong Li83315132019-10-23 17:42:24 +08002309ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002310 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2311{
2312 crConfigVariant value;
2313 switch (static_cast<crParameter>(parameter))
2314 {
2315 case crParameter::crStatus:
2316 {
2317 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2318 {
2319 return ipmi::responseResponseError();
2320 }
2321 std::string* pStatus = std::get_if<std::string>(&value);
2322 if (!pStatus)
2323 {
2324 phosphor::logging::log<phosphor::logging::level::ERR>(
2325 "Error to get ColdRedundancyStatus property");
2326 return ipmi::responseResponseError();
2327 }
2328 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2329 auto status =
2330 server::PowerSupplyRedundancy::convertStatusFromString(
2331 *pStatus);
2332 switch (status)
2333 {
2334 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002335 return ipmi::responseSuccess(parameter,
2336 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002337
2338 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002339 return ipmi::responseSuccess(parameter,
2340 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002341 default:
2342 phosphor::logging::log<phosphor::logging::level::ERR>(
2343 "Error to get valid status");
2344 return ipmi::responseResponseError();
2345 }
2346 }
2347 case crParameter::crFeature:
2348 {
2349 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2350 {
2351 return ipmi::responseResponseError();
2352 }
2353 bool* pResponse = std::get_if<bool>(&value);
2354 if (!pResponse)
2355 {
2356 phosphor::logging::log<phosphor::logging::level::ERR>(
2357 "Error to get ColdRedundancyEnable property");
2358 return ipmi::responseResponseError();
2359 }
2360
Cheng C Yangf41e3342019-09-10 04:47:23 +08002361 return ipmi::responseSuccess(parameter,
2362 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002363 }
2364 case crParameter::rotationFeature:
2365 {
2366 if (getCRConfig(ctx, "RotationEnabled", value))
2367 {
2368 return ipmi::responseResponseError();
2369 }
2370 bool* pResponse = std::get_if<bool>(&value);
2371 if (!pResponse)
2372 {
2373 phosphor::logging::log<phosphor::logging::level::ERR>(
2374 "Error to get RotationEnabled property");
2375 return ipmi::responseResponseError();
2376 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002377 return ipmi::responseSuccess(parameter,
2378 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002379 }
2380 case crParameter::rotationAlgo:
2381 {
2382 if (getCRConfig(ctx, "RotationAlgorithm", value))
2383 {
2384 return ipmi::responseResponseError();
2385 }
2386
2387 std::string* pAlgo = std::get_if<std::string>(&value);
2388 if (!pAlgo)
2389 {
2390 phosphor::logging::log<phosphor::logging::level::ERR>(
2391 "Error to get RotationAlgorithm property");
2392 return ipmi::responseResponseError();
2393 }
Yong Li83315132019-10-23 17:42:24 +08002394 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002395 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2396 auto algo =
2397 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002398
Cheng C Yang773703a2019-08-15 09:41:11 +08002399 switch (algo)
2400 {
2401 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002402 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002403 break;
2404 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002405 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002406 break;
2407 default:
2408 phosphor::logging::log<phosphor::logging::level::ERR>(
2409 "Error to get valid algo");
2410 return ipmi::responseResponseError();
2411 }
2412
2413 if (getCRConfig(ctx, "RotationRankOrder", value))
2414 {
2415 return ipmi::responseResponseError();
2416 }
2417 std::vector<uint8_t>* pResponse =
2418 std::get_if<std::vector<uint8_t>>(&value);
2419 if (!pResponse)
2420 {
2421 phosphor::logging::log<phosphor::logging::level::ERR>(
2422 "Error to get RotationRankOrder property");
2423 return ipmi::responseResponseError();
2424 }
Yong Li83315132019-10-23 17:42:24 +08002425
Cheng C Yang773703a2019-08-15 09:41:11 +08002426 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002427 std::back_inserter(response));
2428
Cheng C Yangf41e3342019-09-10 04:47:23 +08002429 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002430 }
2431 case crParameter::rotationPeriod:
2432 {
2433 if (getCRConfig(ctx, "PeriodOfRotation", value))
2434 {
2435 return ipmi::responseResponseError();
2436 }
2437 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2438 if (!pResponse)
2439 {
2440 phosphor::logging::log<phosphor::logging::level::ERR>(
2441 "Error to get RotationAlgorithm property");
2442 return ipmi::responseResponseError();
2443 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002444 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002445 }
2446 case crParameter::numOfPSU:
2447 {
2448 uint8_t numberOfPSU = getPSUCount();
2449 if (!numberOfPSU)
2450 {
2451 return ipmi::responseResponseError();
2452 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002453 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002454 }
Yong Li19445ab2019-12-20 18:25:29 +08002455 case crParameter::rotationRankOrderEffective:
2456 {
2457 if (getCRConfig(ctx, "RotationRankOrder", value,
2458 "xyz.openbmc_project.PSURedundancy"))
2459 {
2460 return ipmi::responseResponseError();
2461 }
2462 std::vector<uint8_t>* pResponse =
2463 std::get_if<std::vector<uint8_t>>(&value);
2464 if (!pResponse)
2465 {
2466 phosphor::logging::log<phosphor::logging::level::ERR>(
2467 "Error to get effective RotationRankOrder property");
2468 return ipmi::responseResponseError();
2469 }
2470 return ipmi::responseSuccess(parameter, *pResponse);
2471 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002472 default:
2473 {
2474 return ipmi::response(ccParameterNotSupported);
2475 }
2476 }
2477}
2478
Zhu, Yungebe560b02019-04-21 21:19:21 -04002479ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2480 uint8_t faultState,
2481 uint8_t faultGroup,
2482 std::array<uint8_t, 8>& ledStateData)
2483{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002484 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2485 static const std::array<std::string, maxFaultType> faultNames = {
2486 "faultFan", "faultTemp", "faultPower",
2487 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002488
2489 constexpr uint8_t maxFaultSource = 0x4;
2490 constexpr uint8_t skipLEDs = 0xFF;
2491 constexpr uint8_t pinSize = 64;
2492 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002493 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002494
Zhikui Rence4e73f2019-12-06 13:59:47 -08002495 // same pin names need to be defined in dts file
2496 static const std::array<std::array<std::string, groupSize>, groupNum>
2497 faultLedPinNames = {{
2498 "LED_CPU1_CH1_DIMM1_FAULT",
2499 "LED_CPU1_CH1_DIMM2_FAULT",
2500 "LED_CPU1_CH2_DIMM1_FAULT",
2501 "LED_CPU1_CH2_DIMM2_FAULT",
2502 "LED_CPU1_CH3_DIMM1_FAULT",
2503 "LED_CPU1_CH3_DIMM2_FAULT",
2504 "LED_CPU1_CH4_DIMM1_FAULT",
2505 "LED_CPU1_CH4_DIMM2_FAULT",
2506 "LED_CPU1_CH5_DIMM1_FAULT",
2507 "LED_CPU1_CH5_DIMM2_FAULT",
2508 "LED_CPU1_CH6_DIMM1_FAULT",
2509 "LED_CPU1_CH6_DIMM2_FAULT",
2510 "",
2511 "",
2512 "",
2513 "", // end of group1
2514 "LED_CPU2_CH1_DIMM1_FAULT",
2515 "LED_CPU2_CH1_DIMM2_FAULT",
2516 "LED_CPU2_CH2_DIMM1_FAULT",
2517 "LED_CPU2_CH2_DIMM2_FAULT",
2518 "LED_CPU2_CH3_DIMM1_FAULT",
2519 "LED_CPU2_CH3_DIMM2_FAULT",
2520 "LED_CPU2_CH4_DIMM1_FAULT",
2521 "LED_CPU2_CH4_DIMM2_FAULT",
2522 "LED_CPU2_CH5_DIMM1_FAULT",
2523 "LED_CPU2_CH5_DIMM2_FAULT",
2524 "LED_CPU2_CH6_DIMM1_FAULT",
2525 "LED_CPU2_CH6_DIMM2_FAULT",
2526 "",
2527 "",
2528 "",
2529 "", // endof group2
2530 "LED_CPU3_CH1_DIMM1_FAULT",
2531 "LED_CPU3_CH1_DIMM2_FAULT",
2532 "LED_CPU3_CH2_DIMM1_FAULT",
2533 "LED_CPU3_CH2_DIMM2_FAULT",
2534 "LED_CPU3_CH3_DIMM1_FAULT",
2535 "LED_CPU3_CH3_DIMM2_FAULT",
2536 "LED_CPU3_CH4_DIMM1_FAULT",
2537 "LED_CPU3_CH4_DIMM2_FAULT",
2538 "LED_CPU3_CH5_DIMM1_FAULT",
2539 "LED_CPU3_CH5_DIMM2_FAULT",
2540 "LED_CPU3_CH6_DIMM1_FAULT",
2541 "LED_CPU3_CH6_DIMM2_FAULT",
2542 "",
2543 "",
2544 "",
2545 "", // end of group3
2546 "LED_CPU4_CH1_DIMM1_FAULT",
2547 "LED_CPU4_CH1_DIMM2_FAULT",
2548 "LED_CPU4_CH2_DIMM1_FAULT",
2549 "LED_CPU4_CH2_DIMM2_FAULT",
2550 "LED_CPU4_CH3_DIMM1_FAULT",
2551 "LED_CPU4_CH3_DIMM2_FAULT",
2552 "LED_CPU4_CH4_DIMM1_FAULT",
2553 "LED_CPU4_CH4_DIMM2_FAULT",
2554 "LED_CPU4_CH5_DIMM1_FAULT",
2555 "LED_CPU4_CH5_DIMM2_FAULT",
2556 "LED_CPU4_CH6_DIMM1_FAULT",
2557 "LED_CPU4_CH6_DIMM2_FAULT",
2558 "",
2559 "",
2560 "",
2561 "", // end of group4
2562 "LED_FAN1_FAULT",
2563 "LED_FAN2_FAULT",
2564 "LED_FAN3_FAULT",
2565 "LED_FAN4_FAULT",
2566 "LED_FAN5_FAULT",
2567 "LED_FAN6_FAULT",
2568 "LED_FAN7_FAULT",
2569 "LED_FAN8_FAULT",
2570 "",
2571 "",
2572 "",
2573 "",
2574 "",
2575 "",
2576 "",
2577 "" // end of group5
2578 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002579
Zhikui Rence4e73f2019-12-06 13:59:47 -08002580 // Validate the source, fault type --
2581 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2582 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2583 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2584 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2585 // definition differs based on fault type (Byte 2)
2586 // Type Fan=> Group: 0=FanGroupID, FF-not used
2587 // Byte 5-11 00h, not used
2588 // Byte12 FanLedState [7:0]-Fans 7:0
2589 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2590 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2591 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2592 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2593 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2594 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2595 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2596 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002597 if ((sourceId >= maxFaultSource) ||
2598 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2599 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2600 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2601 {
2602 return ipmi::responseParmOutOfRange();
2603 }
2604
Zhikui Rence4e73f2019-12-06 13:59:47 -08002605 size_t pinGroupOffset = 0;
2606 size_t pinGroupMax = pinSize / groupSize;
2607 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002608 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002609 pinGroupOffset = 4;
2610 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002611 }
2612
2613 switch (RemoteFaultType(faultType))
2614 {
2615 case (RemoteFaultType::fan):
2616 case (RemoteFaultType::memory):
2617 {
2618 if (faultGroup == skipLEDs)
2619 {
2620 return ipmi::responseSuccess();
2621 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002622 // calculate led state bit filed count, each byte has 8bits
2623 // the maximum bits will be 8 * 8 bits
2624 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002625
2626 // assemble ledState
2627 uint64_t ledState = 0;
2628 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002629 for (int i = 0; i < sizeof(ledStateData); i++)
2630 {
2631 ledState = (uint64_t)(ledState << 8);
2632 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2633 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002634 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002635
Zhikui Rence4e73f2019-12-06 13:59:47 -08002636 for (int group = 0; group < pinGroupMax; group++)
2637 {
2638 for (int i = 0; i < groupSize; i++)
2639 { // skip non-existing pins
2640 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2641 {
2642 continue;
2643 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002644
Zhikui Rence4e73f2019-12-06 13:59:47 -08002645 gpiod::line line = gpiod::find_line(
2646 faultLedPinNames[group + pinGroupOffset][i]);
2647 if (!line)
2648 {
2649 phosphor::logging::log<phosphor::logging::level::ERR>(
2650 "Not Find Led Gpio Device!",
2651 phosphor::logging::entry(
2652 "DEVICE=%s",
2653 faultLedPinNames[group + pinGroupOffset][i]
2654 .c_str()));
2655 hasError = true;
2656 continue;
2657 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002658
Zhikui Rence4e73f2019-12-06 13:59:47 -08002659 bool activeHigh =
2660 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2661 try
2662 {
2663 line.request(
2664 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2665 activeHigh
2666 ? 0
2667 : gpiod::line_request::FLAG_ACTIVE_LOW});
2668 line.set_value(ledStateBits[i + group * groupSize]);
2669 }
2670 catch (std::system_error&)
2671 {
2672 phosphor::logging::log<phosphor::logging::level::ERR>(
2673 "Error write Led Gpio Device!",
2674 phosphor::logging::entry(
2675 "DEVICE=%s",
2676 faultLedPinNames[group + pinGroupOffset][i]
2677 .c_str()));
2678 hasError = true;
2679 continue;
2680 }
2681 } // for int i
2682 }
2683 if (hasError)
2684 {
2685 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002686 }
2687 break;
2688 }
2689 default:
2690 {
2691 // now only support two fault types
2692 return ipmi::responseParmOutOfRange();
2693 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002694 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002695 return ipmi::responseSuccess();
2696}
2697
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302698ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2699{
2700 uint8_t prodId = 0;
2701 try
2702 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002703 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302704 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002705 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302706 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2707 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002708 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302709 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2710 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302711 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2712 }
2713 catch (std::exception& e)
2714 {
2715 phosphor::logging::log<phosphor::logging::level::ERR>(
2716 "ipmiOEMReadBoardProductId: Product ID read failed!",
2717 phosphor::logging::entry("ERR=%s", e.what()));
2718 }
2719 return ipmi::responseSuccess(prodId);
2720}
2721
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302722/** @brief implements the get security mode command
2723 * @param ctx - ctx pointer
2724 *
2725 * @returns IPMI completion code with following data
2726 * - restriction mode value - As specified in
2727 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2728 * - special mode value - As specified in
2729 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2730 */
2731ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2732{
2733 namespace securityNameSpace =
2734 sdbusplus::xyz::openbmc_project::Control::Security::server;
2735 uint8_t restrictionModeValue = 0;
2736 uint8_t specialModeValue = 0;
2737
2738 boost::system::error_code ec;
2739 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002740 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302741 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2742 restricionModeProperty);
2743 if (ec)
2744 {
2745 phosphor::logging::log<phosphor::logging::level::ERR>(
2746 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2747 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2748 return ipmi::responseUnspecifiedError();
2749 }
2750 restrictionModeValue = static_cast<uint8_t>(
2751 securityNameSpace::RestrictionMode::convertModesFromString(
2752 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302753 auto varSpecialMode =
2754 ctx->bus->yield_method_call<std::variant<std::string>>(
2755 ctx->yield, ec, specialModeService, specialModeBasePath,
2756 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2757 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302758 if (ec)
2759 {
2760 phosphor::logging::log<phosphor::logging::level::ERR>(
2761 "ipmiGetSecurityMode: failed to get SpecialMode property",
2762 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2763 // fall through, let us not worry about SpecialMode property, which is
2764 // not required in user scenario
2765 }
2766 else
2767 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302768 specialModeValue = static_cast<uint8_t>(
2769 securityNameSpace::SpecialMode::convertModesFromString(
2770 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302771 }
2772 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2773}
2774
2775/** @brief implements the set security mode command
2776 * Command allows to upgrade the restriction mode and won't allow
2777 * to downgrade from system interface
2778 * @param ctx - ctx pointer
2779 * @param restrictionMode - restriction mode value to be set.
2780 *
2781 * @returns IPMI completion code
2782 */
2783ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302784 uint8_t restrictionMode,
2785 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302786{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302787#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2788 if (specialMode)
2789 {
2790 return ipmi::responseReqDataLenInvalid();
2791 }
2792#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302793 namespace securityNameSpace =
2794 sdbusplus::xyz::openbmc_project::Control::Security::server;
2795
2796 ChannelInfo chInfo;
2797 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2798 {
2799 phosphor::logging::log<phosphor::logging::level::ERR>(
2800 "ipmiSetSecurityMode: Failed to get Channel Info",
2801 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2802 return ipmi::responseUnspecifiedError();
2803 }
2804 auto reqMode =
2805 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2806
2807 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2808 (reqMode >
2809 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2810 {
2811 return ipmi::responseInvalidFieldRequest();
2812 }
2813
2814 boost::system::error_code ec;
2815 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002816 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302817 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2818 restricionModeProperty);
2819 if (ec)
2820 {
2821 phosphor::logging::log<phosphor::logging::level::ERR>(
2822 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2823 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2824 return ipmi::responseUnspecifiedError();
2825 }
2826 auto currentRestrictionMode =
2827 securityNameSpace::RestrictionMode::convertModesFromString(
2828 std::get<std::string>(varRestrMode));
2829
2830 if (chInfo.mediumType !=
2831 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2832 currentRestrictionMode > reqMode)
2833 {
2834 phosphor::logging::log<phosphor::logging::level::ERR>(
2835 "ipmiSetSecurityMode - Downgrading security mode not supported "
2836 "through system interface",
2837 phosphor::logging::entry(
2838 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2839 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2840 return ipmi::responseCommandNotAvailable();
2841 }
2842
2843 ec.clear();
2844 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002845 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302846 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2847 restricionModeProperty,
2848 static_cast<std::variant<std::string>>(
2849 securityNameSpace::convertForMessage(reqMode)));
2850
2851 if (ec)
2852 {
2853 phosphor::logging::log<phosphor::logging::level::ERR>(
2854 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2855 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2856 return ipmi::responseUnspecifiedError();
2857 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302858
2859#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2860 if (specialMode)
2861 {
2862 ec.clear();
2863 ctx->bus->yield_method_call<>(
2864 ctx->yield, ec, specialModeService, specialModeBasePath,
2865 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2866 specialModeProperty,
2867 static_cast<std::variant<std::string>>(
2868 securityNameSpace::convertForMessage(
2869 static_cast<securityNameSpace::SpecialMode::Modes>(
2870 specialMode.value()))));
2871
2872 if (ec)
2873 {
2874 phosphor::logging::log<phosphor::logging::level::ERR>(
2875 "ipmiSetSecurityMode: failed to set SpecialMode property",
2876 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2877 return ipmi::responseUnspecifiedError();
2878 }
2879 }
2880#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302881 return ipmi::responseSuccess();
2882}
2883
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002884ipmi::RspType<uint8_t /* restore status */>
2885 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2886{
2887 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2888
2889 if (clr != expClr)
2890 {
2891 return ipmi::responseInvalidFieldRequest();
2892 }
2893 constexpr uint8_t cmdStatus = 0;
2894 constexpr uint8_t cmdDefaultRestore = 0xaa;
2895 constexpr uint8_t cmdFullRestore = 0xbb;
2896 constexpr uint8_t cmdFormat = 0xcc;
2897
2898 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2899
2900 switch (cmd)
2901 {
2902 case cmdStatus:
2903 break;
2904 case cmdDefaultRestore:
2905 case cmdFullRestore:
2906 case cmdFormat:
2907 {
2908 // write file to rwfs root
2909 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2910 std::ofstream restoreFile(restoreOpFname);
2911 if (!restoreFile)
2912 {
2913 return ipmi::responseUnspecifiedError();
2914 }
2915 restoreFile << value << "\n";
2916 break;
2917 }
2918 default:
2919 return ipmi::responseInvalidFieldRequest();
2920 }
2921
2922 constexpr uint8_t restorePending = 0;
2923 constexpr uint8_t restoreComplete = 1;
2924
2925 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2926 ? restorePending
2927 : restoreComplete;
2928 return ipmi::responseSuccess(restoreStatus);
2929}
2930
Chen Yugang39736d52019-07-12 16:24:33 +08002931ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2932{
2933 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002934 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002935
2936 try
2937 {
2938 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2939 std::string service =
2940 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2941 Value variant =
2942 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2943 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2944
2945 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2946 std::get<std::string>(variant)))
2947 {
2948 case nmi::NMISource::BMCSourceSignal::None:
2949 bmcSource = static_cast<uint8_t>(NmiSource::none);
2950 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002951 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2952 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002953 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002954 case nmi::NMISource::BMCSourceSignal::Watchdog:
2955 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002956 break;
2957 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2958 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2959 break;
2960 case nmi::NMISource::BMCSourceSignal::MemoryError:
2961 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2962 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002963 case nmi::NMISource::BMCSourceSignal::PciBusError:
2964 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002965 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002966 case nmi::NMISource::BMCSourceSignal::PCH:
2967 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002968 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002969 case nmi::NMISource::BMCSourceSignal::Chipset:
2970 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002971 break;
2972 default:
2973 phosphor::logging::log<phosphor::logging::level::ERR>(
2974 "NMI source: invalid property!",
2975 phosphor::logging::entry(
2976 "PROP=%s", std::get<std::string>(variant).c_str()));
2977 return ipmi::responseResponseError();
2978 }
2979 }
2980 catch (sdbusplus::exception::SdBusError& e)
2981 {
2982 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2983 return ipmi::responseResponseError();
2984 }
2985
2986 return ipmi::responseSuccess(bmcSource);
2987}
2988
2989ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2990{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002991 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002992
2993 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2994 nmi::NMISource::BMCSourceSignal::None;
2995
2996 switch (NmiSource(sourceId))
2997 {
2998 case NmiSource::none:
2999 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3000 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003001 case NmiSource::frontPanelButton:
3002 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003003 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003004 case NmiSource::watchdog:
3005 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003006 break;
3007 case NmiSource::chassisCmd:
3008 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3009 break;
3010 case NmiSource::memoryError:
3011 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3012 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003013 case NmiSource::pciBusError:
3014 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003015 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003016 case NmiSource::pch:
3017 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003018 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003019 case NmiSource::chipset:
3020 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003021 break;
3022 default:
3023 phosphor::logging::log<phosphor::logging::level::ERR>(
3024 "NMI source: invalid property!");
3025 return ipmi::responseResponseError();
3026 }
3027
3028 try
3029 {
3030 // keep NMI signal source
3031 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3032 std::string service =
3033 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003034 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3035 oemNmiBmcSourceObjPathProp,
3036 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003037 // set Enabled property to inform NMI source handling
3038 // to trigger a NMI_OUT BSOD.
3039 // if it's triggered by NMI source property changed,
3040 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3041 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3042 {
3043 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3044 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3045 static_cast<bool>(true));
3046 }
Chen Yugang39736d52019-07-12 16:24:33 +08003047 }
3048 catch (sdbusplus::exception_t& e)
3049 {
3050 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3051 return ipmi::responseResponseError();
3052 }
3053
3054 return ipmi::responseSuccess();
3055}
3056
James Feist63efafa2019-07-24 12:39:21 -07003057namespace dimmOffset
3058{
3059constexpr const char* dimmPower = "DimmPower";
3060constexpr const char* staticCltt = "StaticCltt";
3061constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3062constexpr const char* offsetInterface =
3063 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3064constexpr const char* property = "DimmOffset";
3065
3066}; // namespace dimmOffset
3067
3068ipmi::RspType<>
3069 ipmiOEMSetDimmOffset(uint8_t type,
3070 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3071{
3072 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3073 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3074 {
3075 return ipmi::responseInvalidFieldRequest();
3076 }
3077
3078 if (data.empty())
3079 {
3080 return ipmi::responseInvalidFieldRequest();
3081 }
3082 nlohmann::json json;
3083
3084 std::ifstream jsonStream(dimmOffsetFile);
3085 if (jsonStream.good())
3086 {
3087 json = nlohmann::json::parse(jsonStream, nullptr, false);
3088 if (json.is_discarded())
3089 {
3090 json = nlohmann::json();
3091 }
3092 jsonStream.close();
3093 }
3094
3095 std::string typeName;
3096 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3097 {
3098 typeName = dimmOffset::dimmPower;
3099 }
3100 else
3101 {
3102 typeName = dimmOffset::staticCltt;
3103 }
3104
3105 nlohmann::json& field = json[typeName];
3106
3107 for (const auto& [index, value] : data)
3108 {
3109 field[index] = value;
3110 }
3111
3112 for (nlohmann::json& val : field)
3113 {
3114 if (val == nullptr)
3115 {
3116 val = static_cast<uint8_t>(0);
3117 }
3118 }
3119
3120 std::ofstream output(dimmOffsetFile);
3121 if (!output.good())
3122 {
3123 std::cerr << "Error writing json file\n";
3124 return ipmi::responseResponseError();
3125 }
3126
3127 output << json.dump(4);
3128
3129 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3130 {
3131 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3132
3133 std::variant<std::vector<uint8_t>> offsets =
3134 field.get<std::vector<uint8_t>>();
3135 auto call = bus->new_method_call(
3136 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3137 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3138 try
3139 {
3140 bus->call(call);
3141 }
3142 catch (sdbusplus::exception_t& e)
3143 {
3144 phosphor::logging::log<phosphor::logging::level::ERR>(
3145 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3146 phosphor::logging::entry("ERR=%s", e.what()));
3147 return ipmi::responseResponseError();
3148 }
3149 }
3150
3151 return ipmi::responseSuccess();
3152}
3153
3154ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3155{
3156
3157 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3158 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3159 {
3160 return ipmi::responseInvalidFieldRequest();
3161 }
3162
3163 std::ifstream jsonStream(dimmOffsetFile);
3164
3165 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3166 if (json.is_discarded())
3167 {
3168 std::cerr << "File error in " << dimmOffsetFile << "\n";
3169 return ipmi::responseResponseError();
3170 }
3171
3172 std::string typeName;
3173 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3174 {
3175 typeName = dimmOffset::dimmPower;
3176 }
3177 else
3178 {
3179 typeName = dimmOffset::staticCltt;
3180 }
3181
3182 auto it = json.find(typeName);
3183 if (it == json.end())
3184 {
3185 return ipmi::responseInvalidFieldRequest();
3186 }
3187
3188 if (it->size() <= index)
3189 {
3190 return ipmi::responseInvalidFieldRequest();
3191 }
3192
3193 uint8_t resp = it->at(index).get<uint8_t>();
3194 return ipmi::responseSuccess(resp);
3195}
3196
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003197namespace boot_options
3198{
3199
3200using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3201using IpmiValue = uint8_t;
3202constexpr auto ipmiDefault = 0;
3203
3204std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3205 {0x01, Source::Sources::Network},
3206 {0x02, Source::Sources::Disk},
3207 {0x05, Source::Sources::ExternalMedia},
3208 {0x0f, Source::Sources::RemovableMedia},
3209 {ipmiDefault, Source::Sources::Default}};
3210
3211std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003212 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003213
3214std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3215 {Source::Sources::Network, 0x01},
3216 {Source::Sources::Disk, 0x02},
3217 {Source::Sources::ExternalMedia, 0x05},
3218 {Source::Sources::RemovableMedia, 0x0f},
3219 {Source::Sources::Default, ipmiDefault}};
3220
3221std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003222 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003223
3224static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3225static constexpr auto bootSourceIntf =
3226 "xyz.openbmc_project.Control.Boot.Source";
3227static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3228static constexpr auto persistentObjPath =
3229 "/xyz/openbmc_project/control/host0/boot";
3230static constexpr auto oneTimePath =
3231 "/xyz/openbmc_project/control/host0/boot/one_time";
3232static constexpr auto bootSourceProp = "BootSource";
3233static constexpr auto bootModeProp = "BootMode";
3234static constexpr auto oneTimeBootEnableProp = "Enabled";
3235static constexpr auto httpBootMode =
3236 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3237
3238enum class BootOptionParameter : size_t
3239{
3240 setInProgress = 0x0,
3241 bootFlags = 0x5,
3242};
3243static constexpr uint8_t setComplete = 0x0;
3244static constexpr uint8_t setInProgress = 0x1;
3245static uint8_t transferStatus = setComplete;
3246static constexpr uint8_t setParmVersion = 0x01;
3247static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3248static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3249static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3250static constexpr uint8_t httpBoot = 0xd;
3251static constexpr uint8_t bootSourceMask = 0x3c;
3252
3253} // namespace boot_options
3254
3255ipmi::RspType<uint8_t, // version
3256 uint8_t, // param
3257 uint8_t, // data0, dependent on parameter
3258 std::optional<uint8_t> // data1, dependent on parameter
3259 >
3260 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3261{
3262 using namespace boot_options;
3263 uint8_t bootOption = 0;
3264
3265 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3266 {
3267 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3268 std::nullopt);
3269 }
3270
3271 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3272 {
3273 phosphor::logging::log<phosphor::logging::level::ERR>(
3274 "Unsupported parameter");
3275 return ipmi::responseResponseError();
3276 }
3277
3278 try
3279 {
3280 auto oneTimeEnabled = false;
3281 // read one time Enabled property
3282 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3283 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3284 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3285 enabledIntf, oneTimeBootEnableProp);
3286 oneTimeEnabled = std::get<bool>(variant);
3287
3288 // get BootSource and BootMode properties
3289 // according to oneTimeEnable
3290 auto bootObjPath = oneTimePath;
3291 if (oneTimeEnabled == false)
3292 {
3293 bootObjPath = persistentObjPath;
3294 }
3295
3296 service = getService(*dbus, bootModeIntf, bootObjPath);
3297 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3298 bootModeProp);
3299
3300 auto bootMode =
3301 Mode::convertModesFromString(std::get<std::string>(variant));
3302
3303 service = getService(*dbus, bootSourceIntf, bootObjPath);
3304 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3305 bootSourceProp);
3306
3307 if (std::get<std::string>(variant) == httpBootMode)
3308 {
3309 bootOption = httpBoot;
3310 }
3311 else
3312 {
3313 auto bootSource = Source::convertSourcesFromString(
3314 std::get<std::string>(variant));
3315 bootOption = sourceDbusToIpmi.at(bootSource);
3316 if (Source::Sources::Default == bootSource)
3317 {
3318 bootOption = modeDbusToIpmi.at(bootMode);
3319 }
3320 }
3321
3322 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3323 : setParmBootFlagsValidPermanent;
3324 bootOption <<= 2; // shift for responseconstexpr
3325 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3326 bootOption);
3327 }
3328 catch (sdbusplus::exception_t& e)
3329 {
3330 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3331 return ipmi::responseResponseError();
3332 }
3333}
3334
3335ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3336 std::optional<uint8_t> bootOption)
3337{
3338 using namespace boot_options;
3339 auto oneTimeEnabled = false;
3340
3341 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3342 {
3343 if (bootOption)
3344 {
3345 return ipmi::responseReqDataLenInvalid();
3346 }
3347
3348 if (transferStatus == setInProgress)
3349 {
3350 phosphor::logging::log<phosphor::logging::level::ERR>(
3351 "boot option set in progress!");
3352 return ipmi::responseResponseError();
3353 }
3354
3355 transferStatus = bootParam;
3356 return ipmi::responseSuccess();
3357 }
3358
3359 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3360 {
3361 phosphor::logging::log<phosphor::logging::level::ERR>(
3362 "Unsupported parameter");
3363 return ipmi::responseResponseError();
3364 }
3365
3366 if (!bootOption)
3367 {
3368 return ipmi::responseReqDataLenInvalid();
3369 }
3370
3371 if (((bootOption.value() & bootSourceMask) >> 2) !=
3372 httpBoot) // not http boot, exit
3373 {
3374 phosphor::logging::log<phosphor::logging::level::ERR>(
3375 "wrong boot option parameter!");
3376 return ipmi::responseParmOutOfRange();
3377 }
3378
3379 try
3380 {
3381 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3382 setParmBootFlagsPermanent;
3383
3384 // read one time Enabled property
3385 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3386 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3387 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3388 enabledIntf, oneTimeBootEnableProp);
3389 oneTimeEnabled = std::get<bool>(variant);
3390
3391 /*
3392 * Check if the current boot setting is onetime or permanent, if the
3393 * request in the command is otherwise, then set the "Enabled"
3394 * property in one_time object path to 'True' to indicate onetime
3395 * and 'False' to indicate permanent.
3396 *
3397 * Once the onetime/permanent setting is applied, then the bootMode
3398 * and bootSource is updated for the corresponding object.
3399 */
3400 if (permanent == oneTimeEnabled)
3401 {
3402 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3403 oneTimeBootEnableProp, !permanent);
3404 }
3405
3406 // set BootSource and BootMode properties
3407 // according to oneTimeEnable or persistent
3408 auto bootObjPath = oneTimePath;
3409 if (oneTimeEnabled == false)
3410 {
3411 bootObjPath = persistentObjPath;
3412 }
3413 std::string bootMode =
3414 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3415 std::string bootSource = httpBootMode;
3416
3417 service = getService(*dbus, bootModeIntf, bootObjPath);
3418 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3419 bootMode);
3420
3421 service = getService(*dbus, bootSourceIntf, bootObjPath);
3422 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3423 bootSourceProp, bootSource);
3424 }
3425 catch (sdbusplus::exception_t& e)
3426 {
3427 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3428 return ipmi::responseResponseError();
3429 }
3430
3431 return ipmi::responseSuccess();
3432}
3433
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003434using BasicVariantType =
3435 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3436 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3437 uint16_t, uint8_t, bool>;
3438using PropertyMapType =
3439 boost::container::flat_map<std::string, BasicVariantType>;
3440static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3441 "xyz.openbmc_project.Configuration.PSUPresence"};
3442int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3443 std::vector<uint64_t>& addrTable)
3444{
3445 boost::system::error_code ec;
3446 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3447 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3448 "/xyz/openbmc_project/object_mapper",
3449 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3450 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3451 if (ec)
3452 {
3453 phosphor::logging::log<phosphor::logging::level::ERR>(
3454 "Failed to set dbus property to cold redundancy");
3455 return -1;
3456 }
3457 for (const auto& object : subtree)
3458 {
3459 std::string pathName = object.first;
3460 for (const auto& serviceIface : object.second)
3461 {
3462 std::string serviceName = serviceIface.first;
3463
3464 ec.clear();
3465 PropertyMapType propMap =
3466 ctx->bus->yield_method_call<PropertyMapType>(
3467 ctx->yield, ec, serviceName, pathName,
3468 "org.freedesktop.DBus.Properties", "GetAll",
3469 "xyz.openbmc_project.Configuration.PSUPresence");
3470 if (ec)
3471 {
3472 phosphor::logging::log<phosphor::logging::level::ERR>(
3473 "Failed to set dbus property to cold redundancy");
3474 return -1;
3475 }
3476 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3477 auto psuAddress =
3478 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3479
3480 if (psuBus == nullptr || psuAddress == nullptr)
3481 {
3482 std::cerr << "error finding necessary "
3483 "entry in configuration\n";
3484 return -1;
3485 }
3486 bus = static_cast<uint8_t>(*psuBus);
3487 addrTable = *psuAddress;
3488 return 0;
3489 }
3490 }
3491 return -1;
3492}
3493
3494static const constexpr uint8_t addrOffset = 8;
3495static const constexpr uint8_t psuRevision = 0xd9;
3496static const constexpr uint8_t defaultPSUBus = 7;
3497// Second Minor, Primary Minor, Major
3498static const constexpr size_t verLen = 3;
3499ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3500{
3501 uint8_t bus = defaultPSUBus;
3502 std::vector<uint64_t> addrTable;
3503 std::vector<uint8_t> result;
3504 if (getPSUAddress(ctx, bus, addrTable))
3505 {
3506 std::cerr << "Failed to get PSU bus and address\n";
3507 return ipmi::responseResponseError();
3508 }
3509
3510 for (const auto& slaveAddr : addrTable)
3511 {
3512 std::vector<uint8_t> writeData = {psuRevision};
3513 std::vector<uint8_t> readBuf(verLen);
3514 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3515 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3516
3517 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3518 if (retI2C != ipmi::ccSuccess)
3519 {
3520 for (size_t idx = 0; idx < verLen; idx++)
3521 {
3522 result.emplace_back(0x00);
3523 }
3524 }
3525 else
3526 {
3527 for (const uint8_t& data : readBuf)
3528 {
3529 result.emplace_back(data);
3530 }
3531 }
3532 }
3533
3534 return ipmi::responseSuccess(result);
3535}
3536
AppaRao Puli28972062019-11-11 02:04:45 +05303537/** @brief implements the maximum size of
3538 * bridgeable messages used between KCS and
3539 * IPMB interfacesget security mode command.
3540 *
3541 * @returns IPMI completion code with following data
3542 * - KCS Buffer Size (In multiples of four bytes)
3543 * - IPMB Buffer Size (In multiples of four bytes)
3544 **/
3545ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3546{
3547 // for now this is hard coded; really this number is dependent on
3548 // the BMC kcs driver as well as the host kcs driver....
3549 // we can't know the latter.
3550 uint8_t kcsMaxBufferSize = 63 / 4;
3551 uint8_t ipmbMaxBufferSize = 128 / 4;
3552
3553 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3554}
3555
Jason M. Bills64796042018-10-03 16:51:55 -07003556static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003557{
3558 phosphor::logging::log<phosphor::logging::level::INFO>(
3559 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003560 ipmiPrintAndRegister(intel::netFnGeneral,
3561 intel::general::cmdGetChassisIdentifier, NULL,
3562 ipmiOEMGetChassisIdentifier,
3563 PRIVILEGE_USER); // get chassis identifier
3564
3565 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3566 NULL, ipmiOEMSetSystemGUID,
3567 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003568
3569 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003570 registerHandler(prioOemBase, intel::netFnGeneral,
3571 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3572 ipmiOEMDisableBMCSystemReset);
3573
Jason M. Billsb02bf092019-08-15 13:01:56 -07003574 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003575 registerHandler(prioOemBase, intel::netFnGeneral,
3576 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3577 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003578
Vernon Mauery98bbf692019-09-16 11:14:59 -07003579 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3580 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003581
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003582 registerHandler(prioOemBase, intel::netFnGeneral,
3583 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3584 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003585
Vernon Mauery98bbf692019-09-16 11:14:59 -07003586 ipmiPrintAndRegister(intel::netFnGeneral,
3587 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3588 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303589
Vernon Mauery98bbf692019-09-16 11:14:59 -07003590 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3591 intel::general::cmdSendEmbeddedFWUpdStatus,
3592 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303593
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303594 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3595 Privilege::Admin, ipmiOEMSlotIpmb);
3596
Vernon Mauery98bbf692019-09-16 11:14:59 -07003597 ipmiPrintAndRegister(intel::netFnGeneral,
3598 intel::general::cmdSetPowerRestoreDelay, NULL,
3599 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3600
3601 ipmiPrintAndRegister(intel::netFnGeneral,
3602 intel::general::cmdGetPowerRestoreDelay, NULL,
3603 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3604
3605 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3606 intel::general::cmdSetOEMUser2Activation,
3607 Privilege::Callback, ipmiOEMSetUser2Activation);
3608
3609 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3610 intel::general::cmdSetSpecialUserPassword,
3611 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303612
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003613 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003614 registerHandler(prioOemBase, intel::netFnGeneral,
3615 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3616 ipmiOEMGetProcessorErrConfig);
3617
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003618 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003619 registerHandler(prioOemBase, intel::netFnGeneral,
3620 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3621 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003622
Vernon Mauery98bbf692019-09-16 11:14:59 -07003623 ipmiPrintAndRegister(intel::netFnGeneral,
3624 intel::general::cmdSetShutdownPolicy, NULL,
3625 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003626
Vernon Mauery98bbf692019-09-16 11:14:59 -07003627 ipmiPrintAndRegister(intel::netFnGeneral,
3628 intel::general::cmdGetShutdownPolicy, NULL,
3629 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003630
anil kumar appanaf945eee2019-09-25 23:29:11 +00003631 registerHandler(prioOemBase, intel::netFnGeneral,
3632 intel::general::cmdSetFanConfig, Privilege::User,
3633 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003634
Vernon Mauery98bbf692019-09-16 11:14:59 -07003635 registerHandler(prioOemBase, intel::netFnGeneral,
3636 intel::general::cmdGetFanConfig, Privilege::User,
3637 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003638
Vernon Mauery98bbf692019-09-16 11:14:59 -07003639 registerHandler(prioOemBase, intel::netFnGeneral,
3640 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3641 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003642
Vernon Mauery98bbf692019-09-16 11:14:59 -07003643 registerHandler(prioOemBase, intel::netFnGeneral,
3644 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3645 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003646
Vernon Mauery98bbf692019-09-16 11:14:59 -07003647 registerHandler(prioOemBase, intel::netFnGeneral,
3648 intel::general::cmdSetFscParameter, Privilege::User,
3649 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003650
Vernon Mauery98bbf692019-09-16 11:14:59 -07003651 registerHandler(prioOemBase, intel::netFnGeneral,
3652 intel::general::cmdGetFscParameter, Privilege::User,
3653 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303654
Vernon Mauery98bbf692019-09-16 11:14:59 -07003655 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3656 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3657 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003658
Vernon Mauery98bbf692019-09-16 11:14:59 -07003659 registerHandler(prioOemBase, intel::netFnGeneral,
3660 intel::general::cmdGetNmiStatus, Privilege::User,
3661 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003662
Vernon Mauery98bbf692019-09-16 11:14:59 -07003663 registerHandler(prioOemBase, intel::netFnGeneral,
3664 intel::general::cmdSetNmiStatus, Privilege::Operator,
3665 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003666
Vernon Mauery98bbf692019-09-16 11:14:59 -07003667 registerHandler(prioOemBase, intel::netFnGeneral,
3668 intel::general::cmdGetEfiBootOptions, Privilege::User,
3669 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003670
Vernon Mauery98bbf692019-09-16 11:14:59 -07003671 registerHandler(prioOemBase, intel::netFnGeneral,
3672 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3673 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303674
Vernon Mauery98bbf692019-09-16 11:14:59 -07003675 registerHandler(prioOemBase, intel::netFnGeneral,
3676 intel::general::cmdGetSecurityMode, Privilege::User,
3677 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303678
Vernon Mauery98bbf692019-09-16 11:14:59 -07003679 registerHandler(prioOemBase, intel::netFnGeneral,
3680 intel::general::cmdSetSecurityMode, Privilege::Admin,
3681 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003682
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003683 registerHandler(prioOemBase, intel::netFnGeneral,
3684 intel::general::cmdGetLEDStatus, Privilege::Admin,
3685 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003686
Vernon Mauery98bbf692019-09-16 11:14:59 -07003687 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3688 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3689 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3690
3691 registerHandler(prioOemBase, intel::netFnGeneral,
3692 intel::general::cmdSetFaultIndication, Privilege::Operator,
3693 ipmiOEMSetFaultIndication);
3694
3695 registerHandler(prioOemBase, intel::netFnGeneral,
3696 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3697 ipmiOEMSetCRConfig);
3698
3699 registerHandler(prioOemBase, intel::netFnGeneral,
3700 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3701 ipmiOEMGetCRConfig);
3702
3703 registerHandler(prioOemBase, intel::netFnGeneral,
3704 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003705 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003706
Vernon Mauery98bbf692019-09-16 11:14:59 -07003707 registerHandler(prioOemBase, intel::netFnGeneral,
3708 intel::general::cmdSetDimmOffset, Privilege::Operator,
3709 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003710
Vernon Mauery98bbf692019-09-16 11:14:59 -07003711 registerHandler(prioOemBase, intel::netFnGeneral,
3712 intel::general::cmdGetDimmOffset, Privilege::Operator,
3713 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003714
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003715 registerHandler(prioOemBase, intel::netFnGeneral,
3716 intel::general::cmdGetPSUVersion, Privilege::User,
3717 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303718
3719 registerHandler(prioOemBase, intel::netFnGeneral,
3720 intel::general::cmdGetBufferSize, Privilege::User,
3721 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003722}
3723
3724} // namespace ipmi