blob: fe589de1462bdb23a491a8c85dff658e9aad93cd [file] [log] [blame]
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Patrick Venturec2a07d42020-05-30 16:35:03 -070017#include "types.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070018#include "xyz/openbmc_project/Common/error.hpp"
Kuiying Wang45f04982018-12-26 09:23:08 +080019#include "xyz/openbmc_project/Led/Physical/server.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070020
Jayaprakash Mutyala94204162020-10-23 06:17:56 +000021#include <openssl/crypto.h>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080022#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080023
Chen Yugang7a04f3a2019-10-08 11:12:35 +080024#include <appcommands.hpp>
James Feist91244a62019-02-19 15:04:54 -080025#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080026#include <boost/process/child.hpp>
27#include <boost/process/io.hpp>
Yong Li0669d192019-05-06 14:01:46 +080028#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070029#include <commandutils.hpp>
Zhikui Rence4e73f2019-12-06 13:59:47 -080030#include <gpiod.hpp>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080031#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070032#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070033#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <phosphor-logging/log.hpp>
36#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053037#include <sdbusplus/message/types.hpp>
Chen Yugang97cf96e2019-11-01 08:55:11 +080038#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080039#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
40#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080041#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053042#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053043#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080044
James Feistfcd2d3a2020-05-28 10:38:15 -070045#include <array>
46#include <filesystem>
47#include <iostream>
48#include <regex>
49#include <string>
50#include <variant>
51#include <vector>
52
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080053namespace ipmi
54{
Jason M. Bills64796042018-10-03 16:51:55 -070055static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070056
Jason M. Bills64796042018-10-03 16:51:55 -070057static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080058
Suryakanth Sekard509eb92018-11-15 17:44:11 +053059static constexpr auto ethernetIntf =
60 "xyz.openbmc_project.Network.EthernetInterface";
61static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
62static constexpr auto networkService = "xyz.openbmc_project.Network";
63static constexpr auto networkRoot = "/xyz/openbmc_project/network";
64
Chen Yugang97cf96e2019-11-01 08:55:11 +080065static constexpr const char* oemNmiSourceIntf =
66 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080067static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080068 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080069static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
70static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
71
James Feist63efafa2019-07-24 12:39:21 -070072static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
srikanta mondal2030d7c2020-05-03 17:25:25 +000073static constexpr const char* multiNodeObjPath =
74 "/xyz/openbmc_project/MultiNode/Status";
75static constexpr const char* multiNodeIntf =
76 "xyz.openbmc_project.Chassis.MultiNode";
James Feist63efafa2019-07-24 12:39:21 -070077
Chen Yugang39736d52019-07-12 16:24:33 +080078enum class NmiSource : uint8_t
79{
80 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080081 frontPanelButton = 1,
82 watchdog = 2,
83 chassisCmd = 3,
84 memoryError = 4,
85 pciBusError = 5,
86 pch = 6,
87 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080088};
89
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053090enum class SpecialUserIndex : uint8_t
91{
92 rootUser = 0,
93 atScaleDebugUser = 1
94};
95
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053096static constexpr const char* restricionModeService =
97 "xyz.openbmc_project.RestrictionMode.Manager";
98static constexpr const char* restricionModeBasePath =
99 "/xyz/openbmc_project/control/security/restriction_mode";
100static constexpr const char* restricionModeIntf =
101 "xyz.openbmc_project.Control.Security.RestrictionMode";
102static constexpr const char* restricionModeProperty = "RestrictionMode";
103
104static constexpr const char* specialModeService =
105 "xyz.openbmc_project.SpecialMode";
106static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530107 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530108static constexpr const char* specialModeIntf =
109 "xyz.openbmc_project.Security.SpecialMode";
110static constexpr const char* specialModeProperty = "SpecialMode";
111
112static constexpr const char* dBusPropertyIntf =
113 "org.freedesktop.DBus.Properties";
114static constexpr const char* dBusPropertyGetMethod = "Get";
115static constexpr const char* dBusPropertySetMethod = "Set";
116
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800117// return code: 0 successful
118int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
119{
120 std::string objpath = "/xyz/openbmc_project/FruDevice";
121 std::string intf = "xyz.openbmc_project.FruDeviceManager";
122 std::string service = getService(bus, intf, objpath);
123 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
124 if (valueTree.empty())
125 {
126 phosphor::logging::log<phosphor::logging::level::ERR>(
127 "No object implements interface",
128 phosphor::logging::entry("INTF=%s", intf.c_str()));
129 return -1;
130 }
131
Jason M. Bills64796042018-10-03 16:51:55 -0700132 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800133 {
134 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
135 if (interface == item.second.end())
136 {
137 continue;
138 }
139
140 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
141 if (property == interface->second.end())
142 {
143 continue;
144 }
145
146 try
147 {
148 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700149 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700150 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800151 {
152 phosphor::logging::log<phosphor::logging::level::ERR>(
153 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154 return -1;
155 }
Jason M. Bills64796042018-10-03 16:51:55 -0700156 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800157 return 0;
158 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700159 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800160 {
Jason M. Bills64796042018-10-03 16:51:55 -0700161 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162 return -1;
163 }
164 }
165 return -1;
166}
Jason M. Bills64796042018-10-03 16:51:55 -0700167
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800168// Returns the Chassis Identifier (serial #)
169ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
170 ipmi_request_t request,
171 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700172 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800173 ipmi_context_t context)
174{
175 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700176 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 {
Jason M. Bills64796042018-10-03 16:51:55 -0700178 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 return IPMI_CC_REQ_DATA_LEN_INVALID;
180 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700181 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
182 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 {
Jason M. Bills64796042018-10-03 16:51:55 -0700184 *dataLen = serial.size(); // length will never exceed response length
185 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800186 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700187 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800188 return IPMI_CC_OK;
189 }
Jason M. Bills64796042018-10-03 16:51:55 -0700190 *dataLen = 0;
191 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192}
193
194ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195 ipmi_request_t request,
196 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700197 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800198{
199 static constexpr size_t safeBufferLength = 50;
200 char buf[safeBufferLength] = {0};
201 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
202
Jason M. Bills64796042018-10-03 16:51:55 -0700203 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800204 {
Jason M. Bills64796042018-10-03 16:51:55 -0700205 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800206 return IPMI_CC_REQ_DATA_LEN_INVALID;
207 }
208
Jason M. Bills64796042018-10-03 16:51:55 -0700209 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800210
211 snprintf(
212 buf, safeBufferLength,
213 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
214 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
215 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
216 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
217 Data->node3, Data->node2, Data->node1);
218 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
219 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800220
221 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
222 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700223 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
224 std::string service = getService(*dbus, intf, objpath);
225 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800226 return IPMI_CC_OK;
227}
228
Jason M. Billsb02bf092019-08-15 13:01:56 -0700229ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
230 uint7_t reserved1)
231{
232 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
233
234 try
235 {
236 auto service =
237 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
238 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
239 bmcResetDisablesIntf, "ResetOnSMI",
240 !disableResetOnSMI);
241 }
242 catch (std::exception& e)
243 {
244 phosphor::logging::log<phosphor::logging::level::ERR>(
245 "Failed to set BMC reset disables",
246 phosphor::logging::entry("EXCEPTION=%s", e.what()));
247 return ipmi::responseUnspecifiedError();
248 }
249
250 return ipmi::responseSuccess();
251}
252
253ipmi::RspType<bool, // disableResetOnSMI
254 uint7_t // reserved
255 >
256 ipmiOEMGetBMCResetDisables()
257{
258 bool disableResetOnSMI = true;
259
260 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
261 try
262 {
263 auto service =
264 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
265 Value variant =
266 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
267 bmcResetDisablesIntf, "ResetOnSMI");
268 disableResetOnSMI = !std::get<bool>(variant);
269 }
270 catch (std::exception& e)
271 {
272 phosphor::logging::log<phosphor::logging::level::ERR>(
273 "Failed to get BMC reset disables",
274 phosphor::logging::entry("EXCEPTION=%s", e.what()));
275 return ipmi::responseUnspecifiedError();
276 }
277
278 return ipmi::responseSuccess(disableResetOnSMI, 0);
279}
280
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800281ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
282 ipmi_request_t request, ipmi_response_t response,
283 ipmi_data_len_t dataLen, ipmi_context_t context)
284{
285 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
286
Jason M. Bills64796042018-10-03 16:51:55 -0700287 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800288 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800289 *dataLen = 0;
290 return IPMI_CC_REQ_DATA_LEN_INVALID;
291 }
Jason M. Bills64796042018-10-03 16:51:55 -0700292 std::string idString((char*)data->biosId, data->biosIDLength);
Chalapathi Venkataramashettyfb9f1aa2021-05-07 08:37:07 +0000293 for (auto idChar : idString)
294 {
295 if (!std::isprint(static_cast<unsigned char>(idChar)))
296 {
297 phosphor::logging::log<phosphor::logging::level::ERR>(
298 "BIOS ID contains non printable character");
299 return IPMI_CC_INVALID_FIELD_REQUEST;
300 }
301 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800302
Vernon Mauery15419dd2019-05-24 09:40:30 -0700303 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000304 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
305 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800306 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
308 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700309 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800310 *dataLen = 1;
311 return IPMI_CC_OK;
312}
313
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530314bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
315 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800316{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800317 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530318 std::string bmcVersion;
319 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800320 {
321 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800322 }
323
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530324 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800325 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800326 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800327 MetaRevision revision = rev.value();
328 bmcMajor = revision.major;
329
330 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
331 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
332 }
333
334 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530335 std::string meVersion;
336 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800337 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800338 return false;
339 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530340 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
341 constexpr size_t matchedPhosphor = 6;
342 std::smatch results;
343 if (std::regex_match(meVersion, results, pattern1))
344 {
345 if (results.size() == matchedPhosphor)
346 {
347 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
348 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
349 }
350 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800351 return true;
352}
353
354ipmi::RspType<
355 std::variant<std::string,
356 std::tuple<uint8_t, std::array<uint8_t, 2>,
357 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
358 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
359 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530360 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
361 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530362 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800363{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800364 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
365 {
366 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800367 }
368
369 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800370 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800371 {
372 case OEMDevEntityType::biosId:
373 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530374 // Byte 2&3, Only used with selecting BIOS
375 if (!countToRead || !offset)
376 {
377 return ipmi::responseReqDataLenInvalid();
378 }
379
Vernon Mauery15419dd2019-05-24 09:40:30 -0700380 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800381 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000382 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800383 try
384 {
Yong Li2742b852019-12-16 14:55:11 +0800385 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000386 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800387 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700388 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530389 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800390 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800391 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800392 }
Jason M. Bills64796042018-10-03 16:51:55 -0700393 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530394 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700395 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530396 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700397 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800398 else
399 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530400 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800401 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800402
403 std::string readBuf = {0};
404 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530405 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800406 (readBuf.begin()));
407 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800408 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700409 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800410 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800411 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800412 }
413 }
414 break;
415
416 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800417 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530418 // Byte 2&3, Only used with selecting BIOS
419 if (countToRead || offset)
420 {
421 return ipmi::responseReqDataLenInvalid();
422 }
423
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800424 constexpr const size_t verLen = 2;
425 constexpr const size_t verTotalLen = 10;
426 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
427 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
428 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
429 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
430 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
431 // data0/1: BMC version number; data6/7: ME version number
432 // the others: HSC0/1/2 version number, not avaible.
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530433 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800434 {
435 return ipmi::responseUnspecifiedError();
436 }
437 return ipmi::responseSuccess(
438 std::tuple<
439 uint8_t, std::array<uint8_t, verLen>,
440 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
441 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
442 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
443 }
444 break;
445
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800446 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800447 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530448 // Byte 2&3, Only used with selecting BIOS
449 if (countToRead || offset)
450 {
451 return ipmi::responseReqDataLenInvalid();
452 }
453
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800454 constexpr const size_t sdrLen = 2;
455 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
456 return ipmi::responseSuccess(
457 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
458 readBuf});
459 }
460 break;
461
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800462 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800463 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800464 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800465}
466
467ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
468 ipmi_request_t request, ipmi_response_t response,
469 ipmi_data_len_t dataLen, ipmi_context_t context)
470{
471 if (*dataLen != 0)
472 {
Jason M. Bills64796042018-10-03 16:51:55 -0700473 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800474 return IPMI_CC_REQ_DATA_LEN_INVALID;
475 }
476
477 *dataLen = 1;
478 uint8_t* res = reinterpret_cast<uint8_t*>(response);
479 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
480 // AIC is available so that BIOS will not timeout repeatly which leads to
481 // slow booting.
482 *res = 0; // Byte1=Count of SlotPosition/FruID records.
483 return IPMI_CC_OK;
484}
485
Jason M. Bills64796042018-10-03 16:51:55 -0700486ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
487 ipmi_request_t request,
488 ipmi_response_t response,
489 ipmi_data_len_t dataLen,
490 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800491{
Jason M. Bills64796042018-10-03 16:51:55 -0700492 GetPowerRestoreDelayRes* resp =
493 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
494
495 if (*dataLen != 0)
496 {
497 *dataLen = 0;
498 return IPMI_CC_REQ_DATA_LEN_INVALID;
499 }
500
Vernon Mauery15419dd2019-05-24 09:40:30 -0700501 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700502 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700503 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700504 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700505 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700506 powerRestoreDelayIntf, powerRestoreDelayProp);
507
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700508 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700509 resp->byteLSB = delay;
510 resp->byteMSB = delay >> 8;
511
512 *dataLen = sizeof(GetPowerRestoreDelayRes);
513
514 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800515}
516
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800517static uint8_t bcdToDec(uint8_t val)
518{
519 return ((val / 16 * 10) + (val % 16));
520}
521
522// Allows an update utility or system BIOS to send the status of an embedded
523// firmware update attempt to the BMC. After received, BMC will create a logging
524// record.
525ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
526 uint8_t majorRevision,
527 uint8_t minorRevision,
528 uint32_t auxInfo)
529{
530 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700531 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800532 target = (target & selEvtTargetMask) >> selEvtTargetShift;
533
534 /* make sure the status is 0, 1, or 2 as per the spec */
535 if (status > 2)
536 {
537 return ipmi::response(ipmi::ccInvalidFieldRequest);
538 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700539 /* make sure the target is 0, 1, 2, or 4 as per the spec */
540 if (target > 4 || target == 3)
541 {
542 return ipmi::response(ipmi::ccInvalidFieldRequest);
543 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800544 /*orignal OEM command is to record OEM SEL.
545 But openbmc does not support OEM SEL, so we redirect it to redfish event
546 logging. */
547 std::string buildInfo;
548 std::string action;
549 switch (FWUpdateTarget(target))
550 {
551 case FWUpdateTarget::targetBMC:
552 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700553 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800554 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
555 " BuildID: " + std::to_string(auxInfo);
556 buildInfo += std::to_string(auxInfo);
557 break;
558 case FWUpdateTarget::targetBIOS:
559 firmware = "BIOS";
560 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700561 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800562 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
563 " minor: " +
564 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
565 " ReleaseNumber: " + // ASCII encoded
566 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
567 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
568 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
569 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
570 break;
571 case FWUpdateTarget::targetME:
572 firmware = "ME";
573 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700574 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800575 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
576 " minor2: " +
577 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
578 " build1: " +
579 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
580 " build2: " +
581 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
582 break;
583 case FWUpdateTarget::targetOEMEWS:
584 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700585 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800586 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
587 " BuildID: " + std::to_string(auxInfo);
588 break;
589 }
590
Jason M. Billsdc249272019-04-03 09:58:40 -0700591 static const std::string openBMCMessageRegistryVersion("0.1");
592 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
593
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800594 switch (status)
595 {
596 case 0x0:
597 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700598 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800599 break;
600 case 0x1:
601 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700602 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800603 break;
604 case 0x2:
605 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700606 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800607 break;
608 default:
609 action = "unknown";
610 break;
611 }
612
Jason M. Billsdc249272019-04-03 09:58:40 -0700613 std::string firmwareInstanceStr =
614 firmware + " instance: " + std::to_string(instance);
615 std::string message("[firmware update] " + firmwareInstanceStr +
616 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800617
618 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700619 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
620 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
621 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800622 return ipmi::responseSuccess();
623}
624
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530625ipmi::RspType<uint8_t, std::vector<uint8_t>>
626 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
627 uint2_t slotNumber, uint3_t baseBoardSlotNum,
628 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
629 uint8_t netFn, uint8_t cmd,
630 std::optional<std::vector<uint8_t>> writeData)
631{
632 if (reserved1 || reserved2)
633 {
634 return ipmi::responseInvalidFieldRequest();
635 }
636
637 boost::system::error_code ec;
638 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
639 std::vector<uint8_t>>;
640 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
641 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
642 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
643 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
644 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
645 *writeData);
646 if (ec)
647 {
648 phosphor::logging::log<phosphor::logging::level::ERR>(
649 "Failed to call dbus method SlotIpmbRequest");
650 return ipmi::responseUnspecifiedError();
651 }
652
653 std::vector<uint8_t> dataReceived(0);
654 int status = -1;
655 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
656
657 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
658
659 if (status)
660 {
661 phosphor::logging::log<phosphor::logging::level::ERR>(
662 "Failed to get response from SlotIpmbRequest");
663 return ipmi::responseResponseError();
664 }
665 return ipmi::responseSuccess(cc, dataReceived);
666}
667
Jason M. Bills64796042018-10-03 16:51:55 -0700668ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
669 ipmi_request_t request,
670 ipmi_response_t response,
671 ipmi_data_len_t dataLen,
672 ipmi_context_t context)
673{
674 SetPowerRestoreDelayReq* data =
675 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
676 uint16_t delay = 0;
677
678 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
679 {
680 *dataLen = 0;
681 return IPMI_CC_REQ_DATA_LEN_INVALID;
682 }
683 delay = data->byteMSB;
684 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700685 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700686 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700687 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
688 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700689 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
690 *dataLen = 0;
691
692 return IPMI_CC_OK;
693}
694
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700695static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700696{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700697 static constexpr const char* cpuPresencePathPrefix =
698 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
699 static constexpr const char* cpuPresenceIntf =
700 "xyz.openbmc_project.Inventory.Item";
701 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
702 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
703 try
Jason M. Bills64796042018-10-03 16:51:55 -0700704 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700705 auto service =
706 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
707
708 ipmi::Value result = ipmi::getDbusProperty(
709 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
710 return std::get<bool>(result);
711 }
712 catch (const std::exception& e)
713 {
714 phosphor::logging::log<phosphor::logging::level::INFO>(
715 "Cannot find processor presence",
716 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
717 return false;
718 }
719}
720
721ipmi::RspType<bool, // CATERR Reset Enabled
722 bool, // ERR2 Reset Enabled
723 uint6_t, // reserved
724 uint8_t, // reserved, returns 0x3F
725 uint6_t, // CPU1 CATERR Count
726 uint2_t, // CPU1 Status
727 uint6_t, // CPU2 CATERR Count
728 uint2_t, // CPU2 Status
729 uint6_t, // CPU3 CATERR Count
730 uint2_t, // CPU3 Status
731 uint6_t, // CPU4 CATERR Count
732 uint2_t, // CPU4 Status
733 uint8_t // Crashdump Count
734 >
735 ipmiOEMGetProcessorErrConfig()
736{
737 bool resetOnCATERR = false;
738 bool resetOnERR2 = false;
739 uint6_t cpu1CATERRCount = 0;
740 uint6_t cpu2CATERRCount = 0;
741 uint6_t cpu3CATERRCount = 0;
742 uint6_t cpu4CATERRCount = 0;
743 uint8_t crashdumpCount = 0;
Jason M. Bills24df90f2021-06-15 12:46:13 -0700744 uint2_t cpu1Status = cpuPresent("CPU_1")
745 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
746 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
747 uint2_t cpu2Status = cpuPresent("CPU_2")
748 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
749 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
750 uint2_t cpu3Status = cpuPresent("CPU_3")
751 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
752 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
753 uint2_t cpu4Status = cpuPresent("CPU_4")
754 ? types::enum_cast<uint8_t>(CPUStatus::enabled)
755 : types::enum_cast<uint8_t>(CPUStatus::notPresent);
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700756
757 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
758 try
759 {
760 auto service = ipmi::getService(*busp, processorErrConfigIntf,
761 processorErrConfigObjPath);
762
763 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
764 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
765 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
766 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
767 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
768 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
769 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
770 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
771 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
772 }
773 catch (const std::exception& e)
774 {
775 phosphor::logging::log<phosphor::logging::level::ERR>(
776 "Failed to fetch processor error config",
777 phosphor::logging::entry("ERROR=%s", e.what()));
778 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700779 }
780
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700781 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
782 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
783 cpu2Status, cpu3CATERRCount, cpu3Status,
784 cpu4CATERRCount, cpu4Status, crashdumpCount);
785}
Jason M. Bills64796042018-10-03 16:51:55 -0700786
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700787ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
788 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
789 std::optional<bool> clearCPUErrorCount,
790 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
791{
792 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700793
794 try
795 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700796 auto service = ipmi::getService(*busp, processorErrConfigIntf,
797 processorErrConfigObjPath);
798 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
799 processorErrConfigIntf, "ResetOnCATERR",
800 resetOnCATERR);
801 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
802 processorErrConfigIntf, "ResetOnERR2",
803 resetOnERR2);
804 if (clearCPUErrorCount.value_or(false))
805 {
806 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700807 processorErrConfigIntf, "ErrorCountCPU1",
808 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700809 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700810 processorErrConfigIntf, "ErrorCountCPU2",
811 static_cast<uint8_t>(0));
812 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
813 processorErrConfigIntf, "ErrorCountCPU3",
814 static_cast<uint8_t>(0));
815 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
816 processorErrConfigIntf, "ErrorCountCPU4",
817 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700818 }
819 if (clearCrashdumpCount.value_or(false))
820 {
821 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700822 processorErrConfigIntf, "CrashdumpCount",
823 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700824 }
Jason M. Bills64796042018-10-03 16:51:55 -0700825 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700826 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700827 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800828 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700829 "Failed to set processor error config",
830 phosphor::logging::entry("EXCEPTION=%s", e.what()));
831 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700832 }
833
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700834 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700835}
836
Yong Li703922d2018-11-06 13:25:31 +0800837ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
838 ipmi_request_t request,
839 ipmi_response_t response,
840 ipmi_data_len_t dataLen,
841 ipmi_context_t context)
842{
843 GetOEMShutdownPolicyRes* resp =
844 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
845
846 if (*dataLen != 0)
847 {
848 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800849 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800850 *dataLen = 0;
851 return IPMI_CC_REQ_DATA_LEN_INVALID;
852 }
853
854 *dataLen = 0;
855
856 try
857 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700858 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800859 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700860 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
861 Value variant = getDbusProperty(
862 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
863 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800864
865 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
866 convertPolicyFromString(std::get<std::string>(variant)) ==
867 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
868 NoShutdownOnOCOT)
869 {
870 resp->policy = 0;
871 }
872 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
873 convertPolicyFromString(std::get<std::string>(variant)) ==
874 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
875 Policy::ShutdownOnOCOT)
876 {
877 resp->policy = 1;
878 }
879 else
880 {
881 phosphor::logging::log<phosphor::logging::level::ERR>(
882 "oem_set_shutdown_policy: invalid property!",
883 phosphor::logging::entry(
884 "PROP=%s", std::get<std::string>(variant).c_str()));
885 return IPMI_CC_UNSPECIFIED_ERROR;
886 }
Yong Li703922d2018-11-06 13:25:31 +0800887 // TODO needs to check if it is multi-node products,
888 // policy is only supported on node 3/4
889 resp->policySupport = shutdownPolicySupported;
890 }
891 catch (sdbusplus::exception_t& e)
892 {
893 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
894 return IPMI_CC_UNSPECIFIED_ERROR;
895 }
896
897 *dataLen = sizeof(GetOEMShutdownPolicyRes);
898 return IPMI_CC_OK;
899}
900
901ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
902 ipmi_request_t request,
903 ipmi_response_t response,
904 ipmi_data_len_t dataLen,
905 ipmi_context_t context)
906{
907 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800908 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
909 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
910 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800911
912 // TODO needs to check if it is multi-node products,
913 // policy is only supported on node 3/4
914 if (*dataLen != 1)
915 {
916 phosphor::logging::log<phosphor::logging::level::ERR>(
917 "oem_set_shutdown_policy: invalid input len!");
918 *dataLen = 0;
919 return IPMI_CC_REQ_DATA_LEN_INVALID;
920 }
921
922 *dataLen = 0;
923 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
924 {
925 phosphor::logging::log<phosphor::logging::level::ERR>(
926 "oem_set_shutdown_policy: invalid input!");
927 return IPMI_CC_INVALID_FIELD_REQUEST;
928 }
929
Yong Li0669d192019-05-06 14:01:46 +0800930 if (*req == noShutdownOnOCOT)
931 {
932 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
933 Policy::NoShutdownOnOCOT;
934 }
935 else
936 {
937 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
938 Policy::ShutdownOnOCOT;
939 }
940
Yong Li703922d2018-11-06 13:25:31 +0800941 try
942 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700943 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800944 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700945 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800946 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700947 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800948 oemShutdownPolicyObjPathProp,
949 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800950 }
951 catch (sdbusplus::exception_t& e)
952 {
953 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
954 return IPMI_CC_UNSPECIFIED_ERROR;
955 }
956
957 return IPMI_CC_OK;
958}
959
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530960/** @brief implementation for check the DHCP or not in IPv4
961 * @param[in] Channel - Channel number
962 * @returns true or false.
963 */
964static bool isDHCPEnabled(uint8_t Channel)
965{
966 try
967 {
968 auto ethdevice = getChannelName(Channel);
969 if (ethdevice.empty())
970 {
971 return false;
972 }
973 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700974 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530975 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700976 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
977 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530978 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700979 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530980 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
981 {
982 return true;
983 }
984 else
985 {
986 return false;
987 }
988 }
989 catch (sdbusplus::exception_t& e)
990 {
991 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
992 return true;
993 }
994}
995
996/** @brief implementes for check the DHCP or not in IPv6
997 * @param[in] Channel - Channel number
998 * @returns true or false.
999 */
1000static bool isDHCPIPv6Enabled(uint8_t Channel)
1001{
1002
1003 try
1004 {
1005 auto ethdevice = getChannelName(Channel);
1006 if (ethdevice.empty())
1007 {
1008 return false;
1009 }
1010 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001011 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301012 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001013 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1014 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301015 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001016 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301017 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1018 {
1019 return true;
1020 }
1021 else
1022 {
1023 return false;
1024 }
1025 }
1026 catch (sdbusplus::exception_t& e)
1027 {
1028 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1029 return true;
1030 }
1031}
1032
1033/** @brief implementes the creating of default new user
1034 * @param[in] userName - new username in 16 bytes.
1035 * @param[in] userPassword - new password in 20 bytes
1036 * @returns ipmi completion code.
1037 */
1038ipmi::RspType<> ipmiOEMSetUser2Activation(
1039 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1040 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1041{
1042 bool userState = false;
1043 // Check for System Interface not exist and LAN should be static
1044 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1045 {
1046 ChannelInfo chInfo;
1047 try
1048 {
1049 getChannelInfo(channel, chInfo);
1050 }
1051 catch (sdbusplus::exception_t& e)
1052 {
1053 phosphor::logging::log<phosphor::logging::level::ERR>(
1054 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1055 phosphor::logging::entry("MSG: %s", e.description()));
1056 return ipmi::response(ipmi::ccUnspecifiedError);
1057 }
1058 if (chInfo.mediumType ==
1059 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1060 {
1061 phosphor::logging::log<phosphor::logging::level::ERR>(
1062 "ipmiOEMSetUser2Activation: system interface exist .");
1063 return ipmi::response(ipmi::ccCommandNotAvailable);
1064 }
1065 else
1066 {
1067
1068 if (chInfo.mediumType ==
1069 static_cast<uint8_t>(EChannelMediumType::lan8032))
1070 {
1071 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1072 {
1073 phosphor::logging::log<phosphor::logging::level::ERR>(
1074 "ipmiOEMSetUser2Activation: DHCP enabled .");
1075 return ipmi::response(ipmi::ccCommandNotAvailable);
1076 }
1077 }
1078 }
1079 }
1080 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1081 if (ipmi::ccSuccess ==
1082 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1083 {
1084 if (enabledUsers > 1)
1085 {
1086 phosphor::logging::log<phosphor::logging::level::ERR>(
1087 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1088 return ipmi::response(ipmi::ccCommandNotAvailable);
1089 }
1090 // Check the user 2 is enabled or not
1091 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1092 if (userState == true)
1093 {
1094 phosphor::logging::log<phosphor::logging::level::ERR>(
1095 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1096 return ipmi::response(ipmi::ccCommandNotAvailable);
1097 }
1098 }
1099 else
1100 {
1101 return ipmi::response(ipmi::ccUnspecifiedError);
1102 }
1103
1104#if BYTE_ORDER == LITTLE_ENDIAN
1105 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1106#endif
1107#if BYTE_ORDER == BIG_ENDIAN
1108 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1109#endif
1110
Vernon Mauery037cabd2020-05-14 12:16:01 -07001111 // ipmiUserSetUserName correctly handles char*, possibly non-null
1112 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001113 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1114 sizeof(userName));
1115 const std::string userNameRaw(
1116 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001117
Vernon Mauery037cabd2020-05-14 12:16:01 -07001118 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301119 {
1120 if (ipmi::ccSuccess ==
1121 ipmiUserSetUserPassword(
1122 ipmiDefaultUserId,
1123 reinterpret_cast<const char*>(userPassword.data())))
1124 {
1125 if (ipmi::ccSuccess ==
1126 ipmiUserSetPrivilegeAccess(
1127 ipmiDefaultUserId,
1128 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1129 privAccess, true))
1130 {
1131 phosphor::logging::log<phosphor::logging::level::INFO>(
1132 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001133 OPENSSL_cleanse(userPassword.data(), userPassword.size());
1134
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301135 return ipmi::responseSuccess();
1136 }
1137 }
1138 // we need to delete the default user id which added in this command as
1139 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001140 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301141 phosphor::logging::log<phosphor::logging::level::ERR>(
1142 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001143 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301144 }
1145 else
1146 {
1147 phosphor::logging::log<phosphor::logging::level::ERR>(
1148 "ipmiOEMSetUser2Activation: Setting username failed.");
1149 }
1150
1151 return ipmi::response(ipmi::ccCommandNotAvailable);
1152}
1153
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301154/** @brief implementes executing the linux command
1155 * @param[in] linux command
1156 * @returns status
1157 */
1158
1159static uint8_t executeCmd(const char* path)
1160{
1161 boost::process::child execProg(path);
1162 execProg.wait();
1163
1164 int retCode = execProg.exit_code();
1165 if (retCode)
1166 {
1167 return ipmi::ccUnspecifiedError;
1168 }
1169 return ipmi::ccSuccess;
1170}
1171
1172/** @brief implementes ASD Security event logging
1173 * @param[in] Event message string
1174 * @param[in] Event Severity
1175 * @returns status
1176 */
1177
1178static void atScaleDebugEventlog(std::string msg, int severity)
1179{
1180 std::string eventStr = "OpenBMC.0.1." + msg;
1181 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1182 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1183 eventStr.c_str(), NULL);
1184}
1185
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301186/** @brief implementes setting password for special user
1187 * @param[in] specialUserIndex
1188 * @param[in] userPassword - new password in 20 bytes
1189 * @returns ipmi completion code.
1190 */
1191ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1192 uint8_t specialUserIndex,
1193 std::vector<uint8_t> userPassword)
1194{
1195 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301196 ipmi_ret_t status = ipmi::ccSuccess;
1197
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301198 try
1199 {
1200 getChannelInfo(ctx->channel, chInfo);
1201 }
1202 catch (sdbusplus::exception_t& e)
1203 {
1204 phosphor::logging::log<phosphor::logging::level::ERR>(
1205 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1206 phosphor::logging::entry("MSG: %s", e.description()));
1207 return ipmi::responseUnspecifiedError();
1208 }
1209 if (chInfo.mediumType !=
1210 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1211 {
1212 phosphor::logging::log<phosphor::logging::level::ERR>(
1213 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1214 "interface");
1215 return ipmi::responseCommandNotAvailable();
1216 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301217
1218 // 0 for root user and 1 for AtScaleDebug is allowed
1219 if (specialUserIndex >
1220 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301221 {
1222 phosphor::logging::log<phosphor::logging::level::ERR>(
1223 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1224 return ipmi::responseParmOutOfRange();
1225 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301226 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301227 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301228 constexpr uint8_t minPasswordSizeRequired = 6;
1229 std::string passwd;
1230 if (userPassword.size() < minPasswordSizeRequired ||
1231 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1232 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001233 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301234 return ipmi::responseReqDataLenInvalid();
1235 }
1236 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1237 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001238 // Clear sensitive data
1239 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301240 if (specialUserIndex ==
1241 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1242 {
1243 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1244
1245 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1246 }
1247 else
1248 {
1249 status = ipmiSetSpecialUserPassword("root", passwd);
1250 }
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001251 // Clear sensitive data
1252 OPENSSL_cleanse(&passwd, passwd.length());
1253
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301254 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301255 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301256 else
1257 {
1258 if (specialUserIndex ==
1259 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1260 {
1261 status = executeCmd("passwd -d root");
1262 }
1263 else
1264 {
1265
1266 status = executeCmd("passwd -d asdbg");
1267
1268 if (status == 0)
1269 {
1270 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1271 LOG_INFO);
1272 }
1273 }
1274 return ipmi::response(status);
1275 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301276}
1277
Kuiying Wang45f04982018-12-26 09:23:08 +08001278namespace ledAction
1279{
1280using namespace sdbusplus::xyz::openbmc_project::Led::server;
1281std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001282 {Physical::Action::Off, 0},
1283 {Physical::Action::On, 2},
1284 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001285
1286std::map<uint8_t, std::string> offsetObjPath = {
1287 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1288
1289} // namespace ledAction
1290
1291int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1292 const std::string& objPath, uint8_t& state)
1293{
1294 try
1295 {
1296 std::string service = getService(bus, intf, objPath);
1297 Value stateValue =
1298 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001299 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001300 state = ledAction::actionDbusToIpmi.at(
1301 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1302 convertActionFromString(strState));
1303 }
1304 catch (sdbusplus::exception::SdBusError& e)
1305 {
1306 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1307 return -1;
1308 }
1309 return 0;
1310}
1311
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001312ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001313{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001314 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001315 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001316 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001317 for (auto it = ledAction::offsetObjPath.begin();
1318 it != ledAction::offsetObjPath.end(); ++it)
1319 {
1320 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001321 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001322 {
1323 phosphor::logging::log<phosphor::logging::level::ERR>(
1324 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001325 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001326 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001327 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001328 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001329 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001330}
1331
Yong Li23737fe2019-02-19 08:49:55 +08001332ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1333 ipmi_request_t request,
1334 ipmi_response_t response,
1335 ipmi_data_len_t dataLen,
1336 ipmi_context_t context)
1337{
1338 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1339 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1340
1341 if (*dataLen == 0)
1342 {
1343 phosphor::logging::log<phosphor::logging::level::ERR>(
1344 "CfgHostSerial: invalid input len!",
1345 phosphor::logging::entry("LEN=%d", *dataLen));
1346 return IPMI_CC_REQ_DATA_LEN_INVALID;
1347 }
1348
1349 switch (req->command)
1350 {
1351 case getHostSerialCfgCmd:
1352 {
1353 if (*dataLen != 1)
1354 {
1355 phosphor::logging::log<phosphor::logging::level::ERR>(
1356 "CfgHostSerial: invalid input len!");
1357 *dataLen = 0;
1358 return IPMI_CC_REQ_DATA_LEN_INVALID;
1359 }
1360
1361 *dataLen = 0;
1362
1363 boost::process::ipstream is;
1364 std::vector<std::string> data;
1365 std::string line;
1366 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1367 boost::process::std_out > is);
1368
1369 while (c1.running() && std::getline(is, line) && !line.empty())
1370 {
1371 data.push_back(line);
1372 }
1373
1374 c1.wait();
1375 if (c1.exit_code())
1376 {
1377 phosphor::logging::log<phosphor::logging::level::ERR>(
1378 "CfgHostSerial:: error on execute",
1379 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1380 // Using the default value
1381 *resp = 0;
1382 }
1383 else
1384 {
1385 if (data.size() != 1)
1386 {
1387 phosphor::logging::log<phosphor::logging::level::ERR>(
1388 "CfgHostSerial:: error on read env");
1389 return IPMI_CC_UNSPECIFIED_ERROR;
1390 }
1391 try
1392 {
1393 unsigned long tmp = std::stoul(data[0]);
1394 if (tmp > std::numeric_limits<uint8_t>::max())
1395 {
1396 throw std::out_of_range("Out of range");
1397 }
1398 *resp = static_cast<uint8_t>(tmp);
1399 }
1400 catch (const std::invalid_argument& e)
1401 {
1402 phosphor::logging::log<phosphor::logging::level::ERR>(
1403 "invalid config ",
1404 phosphor::logging::entry("ERR=%s", e.what()));
1405 return IPMI_CC_UNSPECIFIED_ERROR;
1406 }
1407 catch (const std::out_of_range& e)
1408 {
1409 phosphor::logging::log<phosphor::logging::level::ERR>(
1410 "out_of_range config ",
1411 phosphor::logging::entry("ERR=%s", e.what()));
1412 return IPMI_CC_UNSPECIFIED_ERROR;
1413 }
1414 }
1415
1416 *dataLen = 1;
1417 break;
1418 }
1419 case setHostSerialCfgCmd:
1420 {
1421 if (*dataLen != sizeof(CfgHostSerialReq))
1422 {
1423 phosphor::logging::log<phosphor::logging::level::ERR>(
1424 "CfgHostSerial: invalid input len!");
1425 *dataLen = 0;
1426 return IPMI_CC_REQ_DATA_LEN_INVALID;
1427 }
1428
1429 *dataLen = 0;
1430
1431 if (req->parameter > HostSerialCfgParamMax)
1432 {
1433 phosphor::logging::log<phosphor::logging::level::ERR>(
1434 "CfgHostSerial: invalid input!");
1435 return IPMI_CC_INVALID_FIELD_REQUEST;
1436 }
1437
1438 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1439 std::to_string(req->parameter));
1440
1441 c1.wait();
1442 if (c1.exit_code())
1443 {
1444 phosphor::logging::log<phosphor::logging::level::ERR>(
1445 "CfgHostSerial:: error on execute",
1446 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1447 return IPMI_CC_UNSPECIFIED_ERROR;
1448 }
1449 break;
1450 }
1451 default:
1452 phosphor::logging::log<phosphor::logging::level::ERR>(
1453 "CfgHostSerial: invalid input!");
1454 *dataLen = 0;
1455 return IPMI_CC_INVALID_FIELD_REQUEST;
1456 }
1457
1458 return IPMI_CC_OK;
1459}
1460
James Feist91244a62019-02-19 15:04:54 -08001461constexpr const char* thermalModeInterface =
1462 "xyz.openbmc_project.Control.ThermalMode";
1463constexpr const char* thermalModePath =
1464 "/xyz/openbmc_project/control/thermal_mode";
1465
1466bool getFanProfileInterface(
1467 sdbusplus::bus::bus& bus,
1468 boost::container::flat_map<
1469 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1470{
1471 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1472 "GetAll");
1473 call.append(thermalModeInterface);
1474 try
1475 {
1476 auto data = bus.call(call);
1477 data.read(resp);
1478 }
1479 catch (sdbusplus::exception_t& e)
1480 {
1481 phosphor::logging::log<phosphor::logging::level::ERR>(
1482 "getFanProfileInterface: can't get thermal mode!",
1483 phosphor::logging::entry("ERR=%s", e.what()));
1484 return false;
1485 }
1486 return true;
1487}
1488
anil kumar appanaf945eee2019-09-25 23:29:11 +00001489/**@brief implements the OEM set fan config.
1490 * @param selectedFanProfile - fan profile to enable
1491 * @param reserved1
1492 * @param performanceMode - Performance/Acoustic mode
1493 * @param reserved2
1494 * @param setPerformanceMode - set Performance/Acoustic mode
1495 * @param setFanProfile - set fan profile
1496 *
1497 * @return IPMI completion code.
1498 **/
1499ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1500
1501 uint2_t reserved1, bool performanceMode,
1502 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301503 bool setFanProfile,
1504 std::optional<uint8_t> dimmGroupId,
1505 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001506{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001507 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001508 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001509 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001510 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301511
1512 if (dimmGroupId)
1513 {
1514 if (*dimmGroupId >= maxCPUNum)
1515 {
1516 return ipmi::responseInvalidFieldRequest();
1517 }
1518 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1519 {
1520 return ipmi::responseInvalidFieldRequest();
1521 }
1522 }
1523
James Feist91244a62019-02-19 15:04:54 -08001524 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001525 boost::container::flat_map<
1526 std::string, std::variant<std::vector<std::string>, std::string>>
1527 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001528 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1529 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001530 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001531 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001532 }
1533
1534 std::vector<std::string>* supported =
1535 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1536 if (supported == nullptr)
1537 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001538 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001539 }
1540 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001541 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001542 {
James Feist91244a62019-02-19 15:04:54 -08001543 if (performanceMode)
1544 {
1545
1546 if (std::find(supported->begin(), supported->end(),
1547 "Performance") != supported->end())
1548 {
1549 mode = "Performance";
1550 }
1551 }
1552 else
1553 {
James Feist91244a62019-02-19 15:04:54 -08001554 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1555 supported->end())
1556 {
1557 mode = "Acoustic";
1558 }
1559 }
1560 if (mode.empty())
1561 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001562 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001563 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001564
1565 try
1566 {
1567 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1568 thermalModeInterface, "Current", mode);
1569 }
1570 catch (sdbusplus::exception_t& e)
1571 {
1572 phosphor::logging::log<phosphor::logging::level::ERR>(
1573 "ipmiOEMSetFanConfig: can't set thermal mode!",
1574 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1575 return ipmi::responseResponseError();
1576 }
James Feist91244a62019-02-19 15:04:54 -08001577 }
1578
anil kumar appanaf945eee2019-09-25 23:29:11 +00001579 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001580}
1581
James Feist5b693632019-07-09 09:06:09 -07001582ipmi::RspType<uint8_t, // profile support map
1583 uint8_t, // fan control profile enable
1584 uint8_t, // flags
1585 uint32_t // dimm presence bit map
1586 >
1587 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001588{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301589 if (dimmGroupId >= maxCPUNum)
1590 {
1591 return ipmi::responseInvalidFieldRequest();
1592 }
1593
1594 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1595
1596 if (!cpuStatus)
1597 {
1598 return ipmi::responseInvalidFieldRequest();
1599 }
1600
James Feist91244a62019-02-19 15:04:54 -08001601 boost::container::flat_map<
1602 std::string, std::variant<std::vector<std::string>, std::string>>
1603 profileData;
1604
Vernon Mauery15419dd2019-05-24 09:40:30 -07001605 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1606 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001607 {
James Feist5b693632019-07-09 09:06:09 -07001608 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001609 }
1610
1611 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1612
1613 if (current == nullptr)
1614 {
1615 phosphor::logging::log<phosphor::logging::level::ERR>(
1616 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001617 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001618 }
1619 bool performance = (*current == "Performance");
1620
James Feist5b693632019-07-09 09:06:09 -07001621 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001622 if (performance)
1623 {
James Feist5b693632019-07-09 09:06:09 -07001624 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001625 }
1626
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001627 constexpr uint8_t fanControlDefaultProfile = 0x80;
1628 constexpr uint8_t fanControlProfileState = 0x00;
1629 constexpr uint32_t dimmPresenceBitmap = 0x00;
1630
1631 return ipmi::responseSuccess(fanControlDefaultProfile,
1632 fanControlProfileState, flags,
1633 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001634}
James Feist5f957ca2019-03-14 15:33:55 -07001635constexpr const char* cfmLimitSettingPath =
1636 "/xyz/openbmc_project/control/cfm_limit";
1637constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001638constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001639constexpr const size_t legacyPCHSensorNumber = 0x22;
1640constexpr const char* exitAirPathName = "Exit_Air";
1641constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001642constexpr const char* pidConfigurationIface =
1643 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001644
James Feist09f6b602019-08-08 11:30:03 -07001645static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001646{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001647 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001648 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001649 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1650 "/xyz/openbmc_project/object_mapper",
1651 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001652
James Feistacc8a4e2019-04-02 14:23:57 -07001653 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001654 std::string path;
1655 GetSubTreeType resp;
1656 try
1657 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001658 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001659 reply.read(resp);
1660 }
1661 catch (sdbusplus::exception_t&)
1662 {
1663 phosphor::logging::log<phosphor::logging::level::ERR>(
1664 "ipmiOEMGetFscParameter: mapper error");
1665 };
James Feist09f6b602019-08-08 11:30:03 -07001666 auto config =
1667 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1668 return pair.first.find(name) != std::string::npos;
1669 });
James Feistfaa4f222019-03-21 16:21:55 -07001670 if (config != resp.end())
1671 {
1672 path = std::move(config->first);
1673 }
1674 return path;
1675}
James Feist5f957ca2019-03-14 15:33:55 -07001676
James Feistacc8a4e2019-04-02 14:23:57 -07001677// flat map to make alphabetical
1678static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1679{
1680 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001681 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001682 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001683 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1684 "/xyz/openbmc_project/object_mapper",
1685 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001686
1687 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1688 GetSubTreeType resp;
1689
1690 try
1691 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001692 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001693 reply.read(resp);
1694 }
1695 catch (sdbusplus::exception_t&)
1696 {
1697 phosphor::logging::log<phosphor::logging::level::ERR>(
1698 "getFanConfigPaths: mapper error");
1699 };
1700 for (const auto& [path, objects] : resp)
1701 {
1702 if (objects.empty())
1703 {
1704 continue; // should be impossible
1705 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001706
1707 try
1708 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001709 ret.emplace(path,
1710 getAllDbusProperties(*dbus, objects[0].first, path,
1711 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001712 }
1713 catch (sdbusplus::exception_t& e)
1714 {
1715 phosphor::logging::log<phosphor::logging::level::ERR>(
1716 "getPidConfigs: can't get DbusProperties!",
1717 phosphor::logging::entry("ERR=%s", e.what()));
1718 }
James Feistacc8a4e2019-04-02 14:23:57 -07001719 }
1720 return ret;
1721}
1722
1723ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1724{
1725 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1726 if (data.empty())
1727 {
1728 return ipmi::responseResponseError();
1729 }
1730 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1731 for (const auto& [_, pid] : data)
1732 {
1733 auto findClass = pid.find("Class");
1734 if (findClass == pid.end())
1735 {
1736 phosphor::logging::log<phosphor::logging::level::ERR>(
1737 "ipmiOEMGetFscParameter: found illegal pid "
1738 "configurations");
1739 return ipmi::responseResponseError();
1740 }
1741 std::string type = std::get<std::string>(findClass->second);
1742 if (type == "fan")
1743 {
1744 auto findOutLimit = pid.find("OutLimitMin");
1745 if (findOutLimit == pid.end())
1746 {
1747 phosphor::logging::log<phosphor::logging::level::ERR>(
1748 "ipmiOEMGetFscParameter: found illegal pid "
1749 "configurations");
1750 return ipmi::responseResponseError();
1751 }
1752 // get the min out of all the offsets
1753 minOffset = std::min(
1754 minOffset,
1755 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1756 }
1757 }
1758 if (minOffset == std::numeric_limits<uint8_t>::max())
1759 {
1760 phosphor::logging::log<phosphor::logging::level::ERR>(
1761 "ipmiOEMGetFscParameter: found no fan configurations!");
1762 return ipmi::responseResponseError();
1763 }
1764
1765 return ipmi::responseSuccess(minOffset);
1766}
1767
1768ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1769{
1770 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1771 if (data.empty())
1772 {
1773
1774 phosphor::logging::log<phosphor::logging::level::ERR>(
1775 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1776 return ipmi::responseResponseError();
1777 }
1778
Vernon Mauery15419dd2019-05-24 09:40:30 -07001779 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001780 bool found = false;
1781 for (const auto& [path, pid] : data)
1782 {
1783 auto findClass = pid.find("Class");
1784 if (findClass == pid.end())
1785 {
1786
1787 phosphor::logging::log<phosphor::logging::level::ERR>(
1788 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1789 "configurations");
1790 return ipmi::responseResponseError();
1791 }
1792 std::string type = std::get<std::string>(findClass->second);
1793 if (type == "fan")
1794 {
1795 auto findOutLimit = pid.find("OutLimitMin");
1796 if (findOutLimit == pid.end())
1797 {
1798
1799 phosphor::logging::log<phosphor::logging::level::ERR>(
1800 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1801 "configurations");
1802 return ipmi::responseResponseError();
1803 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001804 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001805 path, pidConfigurationIface, "OutLimitMin",
1806 static_cast<double>(offset));
1807 found = true;
1808 }
1809 }
1810 if (!found)
1811 {
1812 phosphor::logging::log<phosphor::logging::level::ERR>(
1813 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1814 return ipmi::responseResponseError();
1815 }
1816
1817 return ipmi::responseSuccess();
1818}
1819
1820ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1821 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001822{
1823 constexpr const size_t disableLimiting = 0x0;
1824
Vernon Mauery15419dd2019-05-24 09:40:30 -07001825 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001826 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001827 {
James Feist09f6b602019-08-08 11:30:03 -07001828 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001829 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001830 {
James Feist09f6b602019-08-08 11:30:03 -07001831 pathName = exitAirPathName;
1832 }
1833 else if (param1 == legacyPCHSensorNumber)
1834 {
1835 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001836 }
1837 else
1838 {
James Feistacc8a4e2019-04-02 14:23:57 -07001839 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001840 }
James Feist09f6b602019-08-08 11:30:03 -07001841 std::string path = getConfigPath(pathName);
1842 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1843 pidConfigurationIface, "SetPoint",
1844 static_cast<double>(param2));
1845 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001846 }
James Feistacc8a4e2019-04-02 14:23:57 -07001847 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001848 {
James Feistacc8a4e2019-04-02 14:23:57 -07001849 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001850
1851 // must be greater than 50 based on eps
1852 if (cfm < 50 && cfm != disableLimiting)
1853 {
James Feistacc8a4e2019-04-02 14:23:57 -07001854 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001855 }
1856
1857 try
1858 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001859 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001860 cfmLimitIface, "Limit",
1861 static_cast<double>(cfm));
1862 }
1863 catch (sdbusplus::exception_t& e)
1864 {
1865 phosphor::logging::log<phosphor::logging::level::ERR>(
1866 "ipmiOEMSetFscParameter: can't set cfm setting!",
1867 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001868 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001869 }
James Feistacc8a4e2019-04-02 14:23:57 -07001870 return ipmi::responseSuccess();
1871 }
1872 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1873 {
1874 constexpr const size_t maxDomainCount = 8;
1875 uint8_t requestedDomainMask = param1;
1876 boost::container::flat_map data = getPidConfigs();
1877 if (data.empty())
1878 {
1879
1880 phosphor::logging::log<phosphor::logging::level::ERR>(
1881 "ipmiOEMSetFscParameter: found no pid configurations!");
1882 return ipmi::responseResponseError();
1883 }
1884 size_t count = 0;
1885 for (const auto& [path, pid] : data)
1886 {
1887 auto findClass = pid.find("Class");
1888 if (findClass == pid.end())
1889 {
1890
1891 phosphor::logging::log<phosphor::logging::level::ERR>(
1892 "ipmiOEMSetFscParameter: found illegal pid "
1893 "configurations");
1894 return ipmi::responseResponseError();
1895 }
1896 std::string type = std::get<std::string>(findClass->second);
1897 if (type == "fan")
1898 {
1899 if (requestedDomainMask & (1 << count))
1900 {
1901 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001902 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001903 pidConfigurationIface, "OutLimitMax",
1904 static_cast<double>(param2));
1905 }
1906 count++;
1907 }
1908 }
1909 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001910 }
1911 else
1912 {
1913 // todo other command parts possibly
1914 // tcontrol is handled in peci now
1915 // fan speed offset not implemented yet
1916 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001917 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001918 }
1919}
1920
James Feistacc8a4e2019-04-02 14:23:57 -07001921ipmi::RspType<
1922 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1923 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001924{
James Feist09f6b602019-08-08 11:30:03 -07001925 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001926
Vernon Mauery15419dd2019-05-24 09:40:30 -07001927 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001928 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001929 {
James Feistacc8a4e2019-04-02 14:23:57 -07001930 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001931 {
James Feistacc8a4e2019-04-02 14:23:57 -07001932 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001933 }
1934
James Feist09f6b602019-08-08 11:30:03 -07001935 std::string pathName;
1936
1937 if (*param == legacyExitAirSensorNumber)
1938 {
1939 pathName = exitAirPathName;
1940 }
1941 else if (*param == legacyPCHSensorNumber)
1942 {
1943 pathName = pchPathName;
1944 }
1945 else
James Feistfaa4f222019-03-21 16:21:55 -07001946 {
James Feistacc8a4e2019-04-02 14:23:57 -07001947 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001948 }
James Feist09f6b602019-08-08 11:30:03 -07001949
1950 uint8_t setpoint = legacyDefaultSetpoint;
1951 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001952 if (path.size())
1953 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001954 Value val = ipmi::getDbusProperty(
1955 *dbus, "xyz.openbmc_project.EntityManager", path,
1956 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001957 setpoint = std::floor(std::get<double>(val) + 0.5);
1958 }
1959
1960 // old implementation used to return the "default" and current, we
1961 // don't make the default readily available so just make both the
1962 // same
James Feistfaa4f222019-03-21 16:21:55 -07001963
James Feistacc8a4e2019-04-02 14:23:57 -07001964 return ipmi::responseSuccess(
1965 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001966 }
James Feistacc8a4e2019-04-02 14:23:57 -07001967 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1968 {
1969 constexpr const size_t maxDomainCount = 8;
1970
1971 if (!param)
1972 {
1973 return ipmi::responseReqDataLenInvalid();
1974 }
1975 uint8_t requestedDomain = *param;
1976 if (requestedDomain >= maxDomainCount)
1977 {
1978 return ipmi::responseInvalidFieldRequest();
1979 }
1980
1981 boost::container::flat_map data = getPidConfigs();
1982 if (data.empty())
1983 {
1984 phosphor::logging::log<phosphor::logging::level::ERR>(
1985 "ipmiOEMGetFscParameter: found no pid configurations!");
1986 return ipmi::responseResponseError();
1987 }
1988 size_t count = 0;
1989 for (const auto& [_, pid] : data)
1990 {
1991 auto findClass = pid.find("Class");
1992 if (findClass == pid.end())
1993 {
1994 phosphor::logging::log<phosphor::logging::level::ERR>(
1995 "ipmiOEMGetFscParameter: found illegal pid "
1996 "configurations");
1997 return ipmi::responseResponseError();
1998 }
1999 std::string type = std::get<std::string>(findClass->second);
2000 if (type == "fan")
2001 {
2002 if (requestedDomain == count)
2003 {
2004 auto findOutLimit = pid.find("OutLimitMax");
2005 if (findOutLimit == pid.end())
2006 {
2007 phosphor::logging::log<phosphor::logging::level::ERR>(
2008 "ipmiOEMGetFscParameter: found illegal pid "
2009 "configurations");
2010 return ipmi::responseResponseError();
2011 }
2012
2013 return ipmi::responseSuccess(
2014 static_cast<uint8_t>(std::floor(
2015 std::get<double>(findOutLimit->second) + 0.5)));
2016 }
2017 else
2018 {
2019 count++;
2020 }
2021 }
2022 }
2023
2024 return ipmi::responseInvalidFieldRequest();
2025 }
2026 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002027 {
2028
2029 /*
2030 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002031 previous behavior didn't seem to prevent this, ignore the check for
2032 now.
James Feist5f957ca2019-03-14 15:33:55 -07002033
James Feistacc8a4e2019-04-02 14:23:57 -07002034 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002035 {
2036 phosphor::logging::log<phosphor::logging::level::ERR>(
2037 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002038 return IPMI_CC_REQ_DATA_LEN_INVALID;
2039 }
2040 */
2041 Value cfmLimit;
2042 Value cfmMaximum;
2043 try
2044 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002045 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002046 cfmLimitSettingPath, cfmLimitIface,
2047 "Limit");
2048 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002049 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002050 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2051 }
2052 catch (sdbusplus::exception_t& e)
2053 {
2054 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002055 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002056 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002057 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002058 }
2059
James Feistacc8a4e2019-04-02 14:23:57 -07002060 double cfmMax = std::get<double>(cfmMaximum);
2061 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002062
James Feistacc8a4e2019-04-02 14:23:57 -07002063 cfmLim = std::floor(cfmLim + 0.5);
2064 cfmMax = std::floor(cfmMax + 0.5);
2065 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2066 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002067
James Feistacc8a4e2019-04-02 14:23:57 -07002068 return ipmi::responseSuccess(
2069 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002070 }
James Feistacc8a4e2019-04-02 14:23:57 -07002071
James Feist5f957ca2019-03-14 15:33:55 -07002072 else
2073 {
2074 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002075 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002076 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002077 }
2078}
2079
Cheng C Yang773703a2019-08-15 09:41:11 +08002080using crConfigVariant =
2081 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2082
2083int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2084 const crConfigVariant& value,
2085 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2086{
2087 boost::system::error_code ec;
2088 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002089 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002090 "/xyz/openbmc_project/control/power_supply_redundancy",
2091 "org.freedesktop.DBus.Properties", "Set",
2092 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2093 if (ec)
2094 {
2095 phosphor::logging::log<phosphor::logging::level::ERR>(
2096 "Failed to set dbus property to cold redundancy");
2097 return -1;
2098 }
2099
2100 return 0;
2101}
2102
Kuiying Wange45333a2020-07-22 22:06:37 +08002103int getCRConfig(
2104 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2105 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2106 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002107{
2108 boost::system::error_code ec;
2109 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002110 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002111 "/xyz/openbmc_project/control/power_supply_redundancy",
2112 "org.freedesktop.DBus.Properties", "Get",
2113 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2114 if (ec)
2115 {
2116 phosphor::logging::log<phosphor::logging::level::ERR>(
2117 "Failed to get dbus property to cold redundancy");
2118 return -1;
2119 }
2120 return 0;
2121}
2122
2123uint8_t getPSUCount(void)
2124{
2125 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2126 ipmi::Value num;
2127 try
2128 {
2129 num = ipmi::getDbusProperty(
2130 *dbus, "xyz.openbmc_project.PSURedundancy",
2131 "/xyz/openbmc_project/control/power_supply_redundancy",
2132 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2133 }
2134 catch (sdbusplus::exception_t& e)
2135 {
2136 phosphor::logging::log<phosphor::logging::level::ERR>(
2137 "Failed to get PSUNumber property from dbus interface");
2138 return 0;
2139 }
2140 uint8_t* pNum = std::get_if<uint8_t>(&num);
2141 if (!pNum)
2142 {
2143 phosphor::logging::log<phosphor::logging::level::ERR>(
2144 "Error to get PSU Number");
2145 return 0;
2146 }
2147 return *pNum;
2148}
2149
2150bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2151{
2152 if (conf.size() < num)
2153 {
2154 phosphor::logging::log<phosphor::logging::level::ERR>(
2155 "Invalid PSU Ranking");
2156 return false;
2157 }
2158 std::set<uint8_t> confSet;
2159 for (uint8_t i = 0; i < num; i++)
2160 {
2161 if (conf[i] > num)
2162 {
2163 phosphor::logging::log<phosphor::logging::level::ERR>(
2164 "PSU Ranking is larger than current PSU number");
2165 return false;
2166 }
2167 confSet.emplace(conf[i]);
2168 }
2169
2170 if (confSet.size() != num)
2171 {
2172 phosphor::logging::log<phosphor::logging::level::ERR>(
2173 "duplicate PSU Ranking");
2174 return false;
2175 }
2176 return true;
2177}
2178
2179enum class crParameter
2180{
2181 crStatus = 0,
2182 crFeature = 1,
2183 rotationFeature = 2,
2184 rotationAlgo = 3,
2185 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002186 numOfPSU = 5,
2187 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002188};
2189
2190constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2191static const constexpr uint32_t oneDay = 0x15180;
2192static const constexpr uint32_t oneMonth = 0xf53700;
2193static const constexpr uint8_t userSpecific = 0x01;
2194static const constexpr uint8_t crSetCompleted = 0;
2195ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2196 uint8_t parameter,
2197 ipmi::message::Payload& payload)
2198{
2199 switch (static_cast<crParameter>(parameter))
2200 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002201 case crParameter::rotationFeature:
2202 {
2203 uint8_t param1;
2204 if (payload.unpack(param1) || !payload.fullyUnpacked())
2205 {
2206 return ipmi::responseReqDataLenInvalid();
2207 }
2208 // Rotation Enable can only be true or false
2209 if (param1 > 1)
2210 {
2211 return ipmi::responseInvalidFieldRequest();
2212 }
2213 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2214 {
2215 return ipmi::responseResponseError();
2216 }
2217 break;
2218 }
2219 case crParameter::rotationAlgo:
2220 {
2221 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2222 std::string algoName;
2223 uint8_t param1;
2224 if (payload.unpack(param1))
2225 {
2226 return ipmi::responseReqDataLenInvalid();
2227 }
2228 switch (param1)
2229 {
2230 case 0:
2231 algoName = "xyz.openbmc_project.Control."
2232 "PowerSupplyRedundancy.Algo.bmcSpecific";
2233 break;
2234 case 1:
2235 algoName = "xyz.openbmc_project.Control."
2236 "PowerSupplyRedundancy.Algo.userSpecific";
2237 break;
2238 default:
2239 return ipmi::responseInvalidFieldRequest();
2240 }
2241 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2242 {
2243 return ipmi::responseResponseError();
2244 }
2245
2246 uint8_t numberOfPSU = getPSUCount();
2247 if (!numberOfPSU)
2248 {
2249 return ipmi::responseResponseError();
2250 }
2251 std::vector<uint8_t> rankOrder;
2252
2253 if (param1 == userSpecific)
2254 {
2255 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2256 {
2257 ipmi::responseReqDataLenInvalid();
2258 }
Yong Li83315132019-10-23 17:42:24 +08002259 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002260 {
2261 return ipmi::responseReqDataLenInvalid();
2262 }
2263
2264 if (!validateCRAlgo(rankOrder, numberOfPSU))
2265 {
2266 return ipmi::responseInvalidFieldRequest();
2267 }
2268 }
2269 else
2270 {
2271 if (rankOrder.size() > 0)
2272 {
2273 return ipmi::responseReqDataLenInvalid();
2274 }
2275 for (uint8_t i = 1; i <= numberOfPSU; i++)
2276 {
2277 rankOrder.emplace_back(i);
2278 }
2279 }
2280 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2281 {
2282 return ipmi::responseResponseError();
2283 }
2284 break;
2285 }
2286 case crParameter::rotationPeriod:
2287 {
2288 // Minimum Rotation period is One day (86400 seconds) and Max
2289 // Rotation Period is 6 month (0xf53700 seconds)
2290 uint32_t period;
2291 if (payload.unpack(period) || !payload.fullyUnpacked())
2292 {
2293 return ipmi::responseReqDataLenInvalid();
2294 }
2295 if ((period < oneDay) || (period > oneMonth))
2296 {
2297 return ipmi::responseInvalidFieldRequest();
2298 }
2299 if (setCRConfig(ctx, "PeriodOfRotation", period))
2300 {
2301 return ipmi::responseResponseError();
2302 }
2303 break;
2304 }
2305 default:
2306 {
2307 return ipmi::response(ccParameterNotSupported);
2308 }
2309 }
2310
Cheng C Yang773703a2019-08-15 09:41:11 +08002311 return ipmi::responseSuccess(crSetCompleted);
2312}
2313
Yong Li83315132019-10-23 17:42:24 +08002314ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002315 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2316{
2317 crConfigVariant value;
2318 switch (static_cast<crParameter>(parameter))
2319 {
2320 case crParameter::crStatus:
2321 {
2322 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2323 {
2324 return ipmi::responseResponseError();
2325 }
2326 std::string* pStatus = std::get_if<std::string>(&value);
2327 if (!pStatus)
2328 {
2329 phosphor::logging::log<phosphor::logging::level::ERR>(
2330 "Error to get ColdRedundancyStatus property");
2331 return ipmi::responseResponseError();
2332 }
2333 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2334 auto status =
2335 server::PowerSupplyRedundancy::convertStatusFromString(
2336 *pStatus);
2337 switch (status)
2338 {
2339 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002340 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002341 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002342
2343 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002344 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002345 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002346 default:
2347 phosphor::logging::log<phosphor::logging::level::ERR>(
2348 "Error to get valid status");
2349 return ipmi::responseResponseError();
2350 }
2351 }
2352 case crParameter::crFeature:
2353 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002354 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002355 {
2356 return ipmi::responseResponseError();
2357 }
2358 bool* pResponse = std::get_if<bool>(&value);
2359 if (!pResponse)
2360 {
2361 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002362 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002363 return ipmi::responseResponseError();
2364 }
2365
Cheng C Yangf41e3342019-09-10 04:47:23 +08002366 return ipmi::responseSuccess(parameter,
2367 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002368 }
2369 case crParameter::rotationFeature:
2370 {
2371 if (getCRConfig(ctx, "RotationEnabled", value))
2372 {
2373 return ipmi::responseResponseError();
2374 }
2375 bool* pResponse = std::get_if<bool>(&value);
2376 if (!pResponse)
2377 {
2378 phosphor::logging::log<phosphor::logging::level::ERR>(
2379 "Error to get RotationEnabled property");
2380 return ipmi::responseResponseError();
2381 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002382 return ipmi::responseSuccess(parameter,
2383 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002384 }
2385 case crParameter::rotationAlgo:
2386 {
2387 if (getCRConfig(ctx, "RotationAlgorithm", value))
2388 {
2389 return ipmi::responseResponseError();
2390 }
2391
2392 std::string* pAlgo = std::get_if<std::string>(&value);
2393 if (!pAlgo)
2394 {
2395 phosphor::logging::log<phosphor::logging::level::ERR>(
2396 "Error to get RotationAlgorithm property");
2397 return ipmi::responseResponseError();
2398 }
Yong Li83315132019-10-23 17:42:24 +08002399 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002400 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2401 auto algo =
2402 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002403
Cheng C Yang773703a2019-08-15 09:41:11 +08002404 switch (algo)
2405 {
2406 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002407 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002408 break;
2409 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002410 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002411 break;
2412 default:
2413 phosphor::logging::log<phosphor::logging::level::ERR>(
2414 "Error to get valid algo");
2415 return ipmi::responseResponseError();
2416 }
2417
2418 if (getCRConfig(ctx, "RotationRankOrder", value))
2419 {
2420 return ipmi::responseResponseError();
2421 }
2422 std::vector<uint8_t>* pResponse =
2423 std::get_if<std::vector<uint8_t>>(&value);
2424 if (!pResponse)
2425 {
2426 phosphor::logging::log<phosphor::logging::level::ERR>(
2427 "Error to get RotationRankOrder property");
2428 return ipmi::responseResponseError();
2429 }
Yong Li83315132019-10-23 17:42:24 +08002430
Cheng C Yang773703a2019-08-15 09:41:11 +08002431 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002432 std::back_inserter(response));
2433
Cheng C Yangf41e3342019-09-10 04:47:23 +08002434 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002435 }
2436 case crParameter::rotationPeriod:
2437 {
2438 if (getCRConfig(ctx, "PeriodOfRotation", value))
2439 {
2440 return ipmi::responseResponseError();
2441 }
2442 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2443 if (!pResponse)
2444 {
2445 phosphor::logging::log<phosphor::logging::level::ERR>(
2446 "Error to get RotationAlgorithm property");
2447 return ipmi::responseResponseError();
2448 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002449 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002450 }
2451 case crParameter::numOfPSU:
2452 {
2453 uint8_t numberOfPSU = getPSUCount();
2454 if (!numberOfPSU)
2455 {
2456 return ipmi::responseResponseError();
2457 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002458 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002459 }
Yong Li19445ab2019-12-20 18:25:29 +08002460 case crParameter::rotationRankOrderEffective:
2461 {
2462 if (getCRConfig(ctx, "RotationRankOrder", value,
2463 "xyz.openbmc_project.PSURedundancy"))
2464 {
2465 return ipmi::responseResponseError();
2466 }
2467 std::vector<uint8_t>* pResponse =
2468 std::get_if<std::vector<uint8_t>>(&value);
2469 if (!pResponse)
2470 {
2471 phosphor::logging::log<phosphor::logging::level::ERR>(
2472 "Error to get effective RotationRankOrder property");
2473 return ipmi::responseResponseError();
2474 }
2475 return ipmi::responseSuccess(parameter, *pResponse);
2476 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002477 default:
2478 {
2479 return ipmi::response(ccParameterNotSupported);
2480 }
2481 }
2482}
2483
Zhu, Yungebe560b02019-04-21 21:19:21 -04002484ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2485 uint8_t faultState,
2486 uint8_t faultGroup,
2487 std::array<uint8_t, 8>& ledStateData)
2488{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002489 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2490 static const std::array<std::string, maxFaultType> faultNames = {
2491 "faultFan", "faultTemp", "faultPower",
2492 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002493
2494 constexpr uint8_t maxFaultSource = 0x4;
2495 constexpr uint8_t skipLEDs = 0xFF;
2496 constexpr uint8_t pinSize = 64;
2497 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002498 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002499
Zhikui Rence4e73f2019-12-06 13:59:47 -08002500 // same pin names need to be defined in dts file
2501 static const std::array<std::array<std::string, groupSize>, groupNum>
2502 faultLedPinNames = {{
2503 "LED_CPU1_CH1_DIMM1_FAULT",
2504 "LED_CPU1_CH1_DIMM2_FAULT",
2505 "LED_CPU1_CH2_DIMM1_FAULT",
2506 "LED_CPU1_CH2_DIMM2_FAULT",
2507 "LED_CPU1_CH3_DIMM1_FAULT",
2508 "LED_CPU1_CH3_DIMM2_FAULT",
2509 "LED_CPU1_CH4_DIMM1_FAULT",
2510 "LED_CPU1_CH4_DIMM2_FAULT",
2511 "LED_CPU1_CH5_DIMM1_FAULT",
2512 "LED_CPU1_CH5_DIMM2_FAULT",
2513 "LED_CPU1_CH6_DIMM1_FAULT",
2514 "LED_CPU1_CH6_DIMM2_FAULT",
2515 "",
2516 "",
2517 "",
2518 "", // end of group1
2519 "LED_CPU2_CH1_DIMM1_FAULT",
2520 "LED_CPU2_CH1_DIMM2_FAULT",
2521 "LED_CPU2_CH2_DIMM1_FAULT",
2522 "LED_CPU2_CH2_DIMM2_FAULT",
2523 "LED_CPU2_CH3_DIMM1_FAULT",
2524 "LED_CPU2_CH3_DIMM2_FAULT",
2525 "LED_CPU2_CH4_DIMM1_FAULT",
2526 "LED_CPU2_CH4_DIMM2_FAULT",
2527 "LED_CPU2_CH5_DIMM1_FAULT",
2528 "LED_CPU2_CH5_DIMM2_FAULT",
2529 "LED_CPU2_CH6_DIMM1_FAULT",
2530 "LED_CPU2_CH6_DIMM2_FAULT",
2531 "",
2532 "",
2533 "",
2534 "", // endof group2
2535 "LED_CPU3_CH1_DIMM1_FAULT",
2536 "LED_CPU3_CH1_DIMM2_FAULT",
2537 "LED_CPU3_CH2_DIMM1_FAULT",
2538 "LED_CPU3_CH2_DIMM2_FAULT",
2539 "LED_CPU3_CH3_DIMM1_FAULT",
2540 "LED_CPU3_CH3_DIMM2_FAULT",
2541 "LED_CPU3_CH4_DIMM1_FAULT",
2542 "LED_CPU3_CH4_DIMM2_FAULT",
2543 "LED_CPU3_CH5_DIMM1_FAULT",
2544 "LED_CPU3_CH5_DIMM2_FAULT",
2545 "LED_CPU3_CH6_DIMM1_FAULT",
2546 "LED_CPU3_CH6_DIMM2_FAULT",
2547 "",
2548 "",
2549 "",
2550 "", // end of group3
2551 "LED_CPU4_CH1_DIMM1_FAULT",
2552 "LED_CPU4_CH1_DIMM2_FAULT",
2553 "LED_CPU4_CH2_DIMM1_FAULT",
2554 "LED_CPU4_CH2_DIMM2_FAULT",
2555 "LED_CPU4_CH3_DIMM1_FAULT",
2556 "LED_CPU4_CH3_DIMM2_FAULT",
2557 "LED_CPU4_CH4_DIMM1_FAULT",
2558 "LED_CPU4_CH4_DIMM2_FAULT",
2559 "LED_CPU4_CH5_DIMM1_FAULT",
2560 "LED_CPU4_CH5_DIMM2_FAULT",
2561 "LED_CPU4_CH6_DIMM1_FAULT",
2562 "LED_CPU4_CH6_DIMM2_FAULT",
2563 "",
2564 "",
2565 "",
2566 "", // end of group4
2567 "LED_FAN1_FAULT",
2568 "LED_FAN2_FAULT",
2569 "LED_FAN3_FAULT",
2570 "LED_FAN4_FAULT",
2571 "LED_FAN5_FAULT",
2572 "LED_FAN6_FAULT",
2573 "LED_FAN7_FAULT",
2574 "LED_FAN8_FAULT",
2575 "",
2576 "",
2577 "",
2578 "",
2579 "",
2580 "",
2581 "",
2582 "" // end of group5
2583 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002584
Zhikui Rence4e73f2019-12-06 13:59:47 -08002585 // Validate the source, fault type --
2586 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2587 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2588 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2589 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2590 // definition differs based on fault type (Byte 2)
2591 // Type Fan=> Group: 0=FanGroupID, FF-not used
2592 // Byte 5-11 00h, not used
2593 // Byte12 FanLedState [7:0]-Fans 7:0
2594 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2595 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2596 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2597 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2598 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2599 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2600 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2601 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002602 if ((sourceId >= maxFaultSource) ||
2603 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2604 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2605 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2606 {
2607 return ipmi::responseParmOutOfRange();
2608 }
2609
Zhikui Rence4e73f2019-12-06 13:59:47 -08002610 size_t pinGroupOffset = 0;
2611 size_t pinGroupMax = pinSize / groupSize;
2612 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002613 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002614 pinGroupOffset = 4;
2615 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002616 }
2617
2618 switch (RemoteFaultType(faultType))
2619 {
2620 case (RemoteFaultType::fan):
2621 case (RemoteFaultType::memory):
2622 {
2623 if (faultGroup == skipLEDs)
2624 {
2625 return ipmi::responseSuccess();
2626 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002627 // calculate led state bit filed count, each byte has 8bits
2628 // the maximum bits will be 8 * 8 bits
2629 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002630
2631 // assemble ledState
2632 uint64_t ledState = 0;
2633 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002634 for (int i = 0; i < sizeof(ledStateData); i++)
2635 {
2636 ledState = (uint64_t)(ledState << 8);
2637 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2638 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002639 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002640
Zhikui Rence4e73f2019-12-06 13:59:47 -08002641 for (int group = 0; group < pinGroupMax; group++)
2642 {
2643 for (int i = 0; i < groupSize; i++)
2644 { // skip non-existing pins
2645 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2646 {
2647 continue;
2648 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002649
Zhikui Rence4e73f2019-12-06 13:59:47 -08002650 gpiod::line line = gpiod::find_line(
2651 faultLedPinNames[group + pinGroupOffset][i]);
2652 if (!line)
2653 {
2654 phosphor::logging::log<phosphor::logging::level::ERR>(
2655 "Not Find Led Gpio Device!",
2656 phosphor::logging::entry(
2657 "DEVICE=%s",
2658 faultLedPinNames[group + pinGroupOffset][i]
2659 .c_str()));
2660 hasError = true;
2661 continue;
2662 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002663
Zhikui Rence4e73f2019-12-06 13:59:47 -08002664 bool activeHigh =
2665 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2666 try
2667 {
2668 line.request(
2669 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2670 activeHigh
2671 ? 0
2672 : gpiod::line_request::FLAG_ACTIVE_LOW});
2673 line.set_value(ledStateBits[i + group * groupSize]);
2674 }
2675 catch (std::system_error&)
2676 {
2677 phosphor::logging::log<phosphor::logging::level::ERR>(
2678 "Error write Led Gpio Device!",
2679 phosphor::logging::entry(
2680 "DEVICE=%s",
2681 faultLedPinNames[group + pinGroupOffset][i]
2682 .c_str()));
2683 hasError = true;
2684 continue;
2685 }
2686 } // for int i
2687 }
2688 if (hasError)
2689 {
2690 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002691 }
2692 break;
2693 }
2694 default:
2695 {
2696 // now only support two fault types
2697 return ipmi::responseParmOutOfRange();
2698 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002699 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002700 return ipmi::responseSuccess();
2701}
2702
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302703ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2704{
2705 uint8_t prodId = 0;
2706 try
2707 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002708 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302709 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002710 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302711 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2712 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002713 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302714 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2715 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302716 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2717 }
2718 catch (std::exception& e)
2719 {
2720 phosphor::logging::log<phosphor::logging::level::ERR>(
2721 "ipmiOEMReadBoardProductId: Product ID read failed!",
2722 phosphor::logging::entry("ERR=%s", e.what()));
2723 }
2724 return ipmi::responseSuccess(prodId);
2725}
2726
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302727/** @brief implements the get security mode command
2728 * @param ctx - ctx pointer
2729 *
2730 * @returns IPMI completion code with following data
2731 * - restriction mode value - As specified in
2732 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2733 * - special mode value - As specified in
2734 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2735 */
2736ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2737{
2738 namespace securityNameSpace =
2739 sdbusplus::xyz::openbmc_project::Control::Security::server;
2740 uint8_t restrictionModeValue = 0;
2741 uint8_t specialModeValue = 0;
2742
2743 boost::system::error_code ec;
2744 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002745 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302746 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2747 restricionModeProperty);
2748 if (ec)
2749 {
2750 phosphor::logging::log<phosphor::logging::level::ERR>(
2751 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2752 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2753 return ipmi::responseUnspecifiedError();
2754 }
2755 restrictionModeValue = static_cast<uint8_t>(
2756 securityNameSpace::RestrictionMode::convertModesFromString(
2757 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302758 auto varSpecialMode =
2759 ctx->bus->yield_method_call<std::variant<std::string>>(
2760 ctx->yield, ec, specialModeService, specialModeBasePath,
2761 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2762 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302763 if (ec)
2764 {
2765 phosphor::logging::log<phosphor::logging::level::ERR>(
2766 "ipmiGetSecurityMode: failed to get SpecialMode property",
2767 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2768 // fall through, let us not worry about SpecialMode property, which is
2769 // not required in user scenario
2770 }
2771 else
2772 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302773 specialModeValue = static_cast<uint8_t>(
2774 securityNameSpace::SpecialMode::convertModesFromString(
2775 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302776 }
2777 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2778}
2779
2780/** @brief implements the set security mode command
2781 * Command allows to upgrade the restriction mode and won't allow
2782 * to downgrade from system interface
2783 * @param ctx - ctx pointer
2784 * @param restrictionMode - restriction mode value to be set.
2785 *
2786 * @returns IPMI completion code
2787 */
2788ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302789 uint8_t restrictionMode,
2790 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302791{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302792#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2793 if (specialMode)
2794 {
2795 return ipmi::responseReqDataLenInvalid();
2796 }
2797#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302798 namespace securityNameSpace =
2799 sdbusplus::xyz::openbmc_project::Control::Security::server;
2800
2801 ChannelInfo chInfo;
2802 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2803 {
2804 phosphor::logging::log<phosphor::logging::level::ERR>(
2805 "ipmiSetSecurityMode: Failed to get Channel Info",
2806 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2807 return ipmi::responseUnspecifiedError();
2808 }
2809 auto reqMode =
2810 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2811
2812 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2813 (reqMode >
2814 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2815 {
2816 return ipmi::responseInvalidFieldRequest();
2817 }
2818
2819 boost::system::error_code ec;
2820 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002821 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302822 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2823 restricionModeProperty);
2824 if (ec)
2825 {
2826 phosphor::logging::log<phosphor::logging::level::ERR>(
2827 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2828 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2829 return ipmi::responseUnspecifiedError();
2830 }
2831 auto currentRestrictionMode =
2832 securityNameSpace::RestrictionMode::convertModesFromString(
2833 std::get<std::string>(varRestrMode));
2834
2835 if (chInfo.mediumType !=
2836 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2837 currentRestrictionMode > reqMode)
2838 {
2839 phosphor::logging::log<phosphor::logging::level::ERR>(
2840 "ipmiSetSecurityMode - Downgrading security mode not supported "
2841 "through system interface",
2842 phosphor::logging::entry(
2843 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2844 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2845 return ipmi::responseCommandNotAvailable();
2846 }
2847
2848 ec.clear();
2849 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002850 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302851 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2852 restricionModeProperty,
2853 static_cast<std::variant<std::string>>(
2854 securityNameSpace::convertForMessage(reqMode)));
2855
2856 if (ec)
2857 {
2858 phosphor::logging::log<phosphor::logging::level::ERR>(
2859 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2860 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2861 return ipmi::responseUnspecifiedError();
2862 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302863
2864#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2865 if (specialMode)
2866 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00002867 constexpr uint8_t mfgMode = 0x01;
2868 // Manufacturing mode is reserved. So can't enable this mode.
2869 if (specialMode.value() == mfgMode)
2870 {
2871 phosphor::logging::log<phosphor::logging::level::INFO>(
2872 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
2873 return ipmi::responseInvalidFieldRequest();
2874 }
2875
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302876 ec.clear();
2877 ctx->bus->yield_method_call<>(
2878 ctx->yield, ec, specialModeService, specialModeBasePath,
2879 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2880 specialModeProperty,
2881 static_cast<std::variant<std::string>>(
2882 securityNameSpace::convertForMessage(
2883 static_cast<securityNameSpace::SpecialMode::Modes>(
2884 specialMode.value()))));
2885
2886 if (ec)
2887 {
2888 phosphor::logging::log<phosphor::logging::level::ERR>(
2889 "ipmiSetSecurityMode: failed to set SpecialMode property",
2890 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2891 return ipmi::responseUnspecifiedError();
2892 }
2893 }
2894#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302895 return ipmi::responseSuccess();
2896}
2897
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002898ipmi::RspType<uint8_t /* restore status */>
2899 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2900{
2901 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2902
2903 if (clr != expClr)
2904 {
2905 return ipmi::responseInvalidFieldRequest();
2906 }
2907 constexpr uint8_t cmdStatus = 0;
2908 constexpr uint8_t cmdDefaultRestore = 0xaa;
2909 constexpr uint8_t cmdFullRestore = 0xbb;
2910 constexpr uint8_t cmdFormat = 0xcc;
2911
2912 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2913
2914 switch (cmd)
2915 {
2916 case cmdStatus:
2917 break;
2918 case cmdDefaultRestore:
2919 case cmdFullRestore:
2920 case cmdFormat:
2921 {
2922 // write file to rwfs root
2923 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2924 std::ofstream restoreFile(restoreOpFname);
2925 if (!restoreFile)
2926 {
2927 return ipmi::responseUnspecifiedError();
2928 }
2929 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05302930
2931 phosphor::logging::log<phosphor::logging::level::WARNING>(
2932 "Restore to default will be performed on next BMC boot",
2933 phosphor::logging::entry("ACTION=0x%0X", cmd));
2934
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002935 break;
2936 }
2937 default:
2938 return ipmi::responseInvalidFieldRequest();
2939 }
2940
2941 constexpr uint8_t restorePending = 0;
2942 constexpr uint8_t restoreComplete = 1;
2943
2944 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2945 ? restorePending
2946 : restoreComplete;
2947 return ipmi::responseSuccess(restoreStatus);
2948}
2949
Chen Yugang39736d52019-07-12 16:24:33 +08002950ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2951{
2952 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002953 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002954
2955 try
2956 {
2957 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2958 std::string service =
2959 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2960 Value variant =
2961 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2962 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2963
2964 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2965 std::get<std::string>(variant)))
2966 {
2967 case nmi::NMISource::BMCSourceSignal::None:
2968 bmcSource = static_cast<uint8_t>(NmiSource::none);
2969 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002970 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2971 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002972 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002973 case nmi::NMISource::BMCSourceSignal::Watchdog:
2974 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002975 break;
2976 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2977 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2978 break;
2979 case nmi::NMISource::BMCSourceSignal::MemoryError:
2980 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2981 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002982 case nmi::NMISource::BMCSourceSignal::PciBusError:
2983 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002984 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002985 case nmi::NMISource::BMCSourceSignal::PCH:
2986 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002987 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002988 case nmi::NMISource::BMCSourceSignal::Chipset:
2989 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002990 break;
2991 default:
2992 phosphor::logging::log<phosphor::logging::level::ERR>(
2993 "NMI source: invalid property!",
2994 phosphor::logging::entry(
2995 "PROP=%s", std::get<std::string>(variant).c_str()));
2996 return ipmi::responseResponseError();
2997 }
2998 }
2999 catch (sdbusplus::exception::SdBusError& e)
3000 {
3001 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3002 return ipmi::responseResponseError();
3003 }
3004
3005 return ipmi::responseSuccess(bmcSource);
3006}
3007
3008ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3009{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003010 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003011
3012 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3013 nmi::NMISource::BMCSourceSignal::None;
3014
3015 switch (NmiSource(sourceId))
3016 {
3017 case NmiSource::none:
3018 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3019 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003020 case NmiSource::frontPanelButton:
3021 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003022 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003023 case NmiSource::watchdog:
3024 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003025 break;
3026 case NmiSource::chassisCmd:
3027 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3028 break;
3029 case NmiSource::memoryError:
3030 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3031 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003032 case NmiSource::pciBusError:
3033 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003034 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003035 case NmiSource::pch:
3036 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003037 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003038 case NmiSource::chipset:
3039 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003040 break;
3041 default:
3042 phosphor::logging::log<phosphor::logging::level::ERR>(
3043 "NMI source: invalid property!");
3044 return ipmi::responseResponseError();
3045 }
3046
3047 try
3048 {
3049 // keep NMI signal source
3050 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3051 std::string service =
3052 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003053 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3054 oemNmiBmcSourceObjPathProp,
3055 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003056 // set Enabled property to inform NMI source handling
3057 // to trigger a NMI_OUT BSOD.
3058 // if it's triggered by NMI source property changed,
3059 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3060 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3061 {
3062 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3063 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3064 static_cast<bool>(true));
3065 }
Chen Yugang39736d52019-07-12 16:24:33 +08003066 }
3067 catch (sdbusplus::exception_t& e)
3068 {
3069 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3070 return ipmi::responseResponseError();
3071 }
3072
3073 return ipmi::responseSuccess();
3074}
3075
James Feist63efafa2019-07-24 12:39:21 -07003076namespace dimmOffset
3077{
3078constexpr const char* dimmPower = "DimmPower";
3079constexpr const char* staticCltt = "StaticCltt";
3080constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3081constexpr const char* offsetInterface =
3082 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3083constexpr const char* property = "DimmOffset";
3084
3085}; // namespace dimmOffset
3086
3087ipmi::RspType<>
3088 ipmiOEMSetDimmOffset(uint8_t type,
3089 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3090{
3091 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3092 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3093 {
3094 return ipmi::responseInvalidFieldRequest();
3095 }
3096
3097 if (data.empty())
3098 {
3099 return ipmi::responseInvalidFieldRequest();
3100 }
3101 nlohmann::json json;
3102
3103 std::ifstream jsonStream(dimmOffsetFile);
3104 if (jsonStream.good())
3105 {
3106 json = nlohmann::json::parse(jsonStream, nullptr, false);
3107 if (json.is_discarded())
3108 {
3109 json = nlohmann::json();
3110 }
3111 jsonStream.close();
3112 }
3113
3114 std::string typeName;
3115 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3116 {
3117 typeName = dimmOffset::dimmPower;
3118 }
3119 else
3120 {
3121 typeName = dimmOffset::staticCltt;
3122 }
3123
3124 nlohmann::json& field = json[typeName];
3125
3126 for (const auto& [index, value] : data)
3127 {
3128 field[index] = value;
3129 }
3130
3131 for (nlohmann::json& val : field)
3132 {
3133 if (val == nullptr)
3134 {
3135 val = static_cast<uint8_t>(0);
3136 }
3137 }
3138
3139 std::ofstream output(dimmOffsetFile);
3140 if (!output.good())
3141 {
3142 std::cerr << "Error writing json file\n";
3143 return ipmi::responseResponseError();
3144 }
3145
3146 output << json.dump(4);
3147
3148 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3149 {
3150 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3151
3152 std::variant<std::vector<uint8_t>> offsets =
3153 field.get<std::vector<uint8_t>>();
3154 auto call = bus->new_method_call(
3155 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3156 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3157 try
3158 {
3159 bus->call(call);
3160 }
3161 catch (sdbusplus::exception_t& e)
3162 {
3163 phosphor::logging::log<phosphor::logging::level::ERR>(
3164 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3165 phosphor::logging::entry("ERR=%s", e.what()));
3166 return ipmi::responseResponseError();
3167 }
3168 }
3169
3170 return ipmi::responseSuccess();
3171}
3172
3173ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3174{
3175
3176 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3177 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3178 {
3179 return ipmi::responseInvalidFieldRequest();
3180 }
3181
3182 std::ifstream jsonStream(dimmOffsetFile);
3183
3184 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3185 if (json.is_discarded())
3186 {
3187 std::cerr << "File error in " << dimmOffsetFile << "\n";
3188 return ipmi::responseResponseError();
3189 }
3190
3191 std::string typeName;
3192 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3193 {
3194 typeName = dimmOffset::dimmPower;
3195 }
3196 else
3197 {
3198 typeName = dimmOffset::staticCltt;
3199 }
3200
3201 auto it = json.find(typeName);
3202 if (it == json.end())
3203 {
3204 return ipmi::responseInvalidFieldRequest();
3205 }
3206
3207 if (it->size() <= index)
3208 {
3209 return ipmi::responseInvalidFieldRequest();
3210 }
3211
3212 uint8_t resp = it->at(index).get<uint8_t>();
3213 return ipmi::responseSuccess(resp);
3214}
3215
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003216namespace boot_options
3217{
3218
3219using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3220using IpmiValue = uint8_t;
3221constexpr auto ipmiDefault = 0;
3222
3223std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3224 {0x01, Source::Sources::Network},
3225 {0x02, Source::Sources::Disk},
3226 {0x05, Source::Sources::ExternalMedia},
3227 {0x0f, Source::Sources::RemovableMedia},
3228 {ipmiDefault, Source::Sources::Default}};
3229
3230std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003231 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003232
3233std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3234 {Source::Sources::Network, 0x01},
3235 {Source::Sources::Disk, 0x02},
3236 {Source::Sources::ExternalMedia, 0x05},
3237 {Source::Sources::RemovableMedia, 0x0f},
3238 {Source::Sources::Default, ipmiDefault}};
3239
3240std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003241 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003242
3243static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3244static constexpr auto bootSourceIntf =
3245 "xyz.openbmc_project.Control.Boot.Source";
3246static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3247static constexpr auto persistentObjPath =
3248 "/xyz/openbmc_project/control/host0/boot";
3249static constexpr auto oneTimePath =
3250 "/xyz/openbmc_project/control/host0/boot/one_time";
3251static constexpr auto bootSourceProp = "BootSource";
3252static constexpr auto bootModeProp = "BootMode";
3253static constexpr auto oneTimeBootEnableProp = "Enabled";
3254static constexpr auto httpBootMode =
3255 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3256
3257enum class BootOptionParameter : size_t
3258{
3259 setInProgress = 0x0,
3260 bootFlags = 0x5,
3261};
3262static constexpr uint8_t setComplete = 0x0;
3263static constexpr uint8_t setInProgress = 0x1;
3264static uint8_t transferStatus = setComplete;
3265static constexpr uint8_t setParmVersion = 0x01;
3266static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3267static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3268static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3269static constexpr uint8_t httpBoot = 0xd;
3270static constexpr uint8_t bootSourceMask = 0x3c;
3271
3272} // namespace boot_options
3273
3274ipmi::RspType<uint8_t, // version
3275 uint8_t, // param
3276 uint8_t, // data0, dependent on parameter
3277 std::optional<uint8_t> // data1, dependent on parameter
3278 >
3279 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3280{
3281 using namespace boot_options;
3282 uint8_t bootOption = 0;
3283
3284 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3285 {
3286 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3287 std::nullopt);
3288 }
3289
3290 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3291 {
3292 phosphor::logging::log<phosphor::logging::level::ERR>(
3293 "Unsupported parameter");
3294 return ipmi::responseResponseError();
3295 }
3296
3297 try
3298 {
3299 auto oneTimeEnabled = false;
3300 // read one time Enabled property
3301 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3302 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3303 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3304 enabledIntf, oneTimeBootEnableProp);
3305 oneTimeEnabled = std::get<bool>(variant);
3306
3307 // get BootSource and BootMode properties
3308 // according to oneTimeEnable
3309 auto bootObjPath = oneTimePath;
3310 if (oneTimeEnabled == false)
3311 {
3312 bootObjPath = persistentObjPath;
3313 }
3314
3315 service = getService(*dbus, bootModeIntf, bootObjPath);
3316 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3317 bootModeProp);
3318
3319 auto bootMode =
3320 Mode::convertModesFromString(std::get<std::string>(variant));
3321
3322 service = getService(*dbus, bootSourceIntf, bootObjPath);
3323 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3324 bootSourceProp);
3325
3326 if (std::get<std::string>(variant) == httpBootMode)
3327 {
3328 bootOption = httpBoot;
3329 }
3330 else
3331 {
3332 auto bootSource = Source::convertSourcesFromString(
3333 std::get<std::string>(variant));
3334 bootOption = sourceDbusToIpmi.at(bootSource);
3335 if (Source::Sources::Default == bootSource)
3336 {
3337 bootOption = modeDbusToIpmi.at(bootMode);
3338 }
3339 }
3340
3341 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3342 : setParmBootFlagsValidPermanent;
3343 bootOption <<= 2; // shift for responseconstexpr
3344 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3345 bootOption);
3346 }
3347 catch (sdbusplus::exception_t& e)
3348 {
3349 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3350 return ipmi::responseResponseError();
3351 }
3352}
3353
3354ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3355 std::optional<uint8_t> bootOption)
3356{
3357 using namespace boot_options;
3358 auto oneTimeEnabled = false;
3359
3360 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3361 {
3362 if (bootOption)
3363 {
3364 return ipmi::responseReqDataLenInvalid();
3365 }
3366
3367 if (transferStatus == setInProgress)
3368 {
3369 phosphor::logging::log<phosphor::logging::level::ERR>(
3370 "boot option set in progress!");
3371 return ipmi::responseResponseError();
3372 }
3373
3374 transferStatus = bootParam;
3375 return ipmi::responseSuccess();
3376 }
3377
3378 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3379 {
3380 phosphor::logging::log<phosphor::logging::level::ERR>(
3381 "Unsupported parameter");
3382 return ipmi::responseResponseError();
3383 }
3384
3385 if (!bootOption)
3386 {
3387 return ipmi::responseReqDataLenInvalid();
3388 }
3389
3390 if (((bootOption.value() & bootSourceMask) >> 2) !=
3391 httpBoot) // not http boot, exit
3392 {
3393 phosphor::logging::log<phosphor::logging::level::ERR>(
3394 "wrong boot option parameter!");
3395 return ipmi::responseParmOutOfRange();
3396 }
3397
3398 try
3399 {
3400 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3401 setParmBootFlagsPermanent;
3402
3403 // read one time Enabled property
3404 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3405 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3406 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3407 enabledIntf, oneTimeBootEnableProp);
3408 oneTimeEnabled = std::get<bool>(variant);
3409
3410 /*
3411 * Check if the current boot setting is onetime or permanent, if the
3412 * request in the command is otherwise, then set the "Enabled"
3413 * property in one_time object path to 'True' to indicate onetime
3414 * and 'False' to indicate permanent.
3415 *
3416 * Once the onetime/permanent setting is applied, then the bootMode
3417 * and bootSource is updated for the corresponding object.
3418 */
3419 if (permanent == oneTimeEnabled)
3420 {
3421 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3422 oneTimeBootEnableProp, !permanent);
3423 }
3424
3425 // set BootSource and BootMode properties
3426 // according to oneTimeEnable or persistent
3427 auto bootObjPath = oneTimePath;
3428 if (oneTimeEnabled == false)
3429 {
3430 bootObjPath = persistentObjPath;
3431 }
3432 std::string bootMode =
3433 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3434 std::string bootSource = httpBootMode;
3435
3436 service = getService(*dbus, bootModeIntf, bootObjPath);
3437 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3438 bootMode);
3439
3440 service = getService(*dbus, bootSourceIntf, bootObjPath);
3441 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3442 bootSourceProp, bootSource);
3443 }
3444 catch (sdbusplus::exception_t& e)
3445 {
3446 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3447 return ipmi::responseResponseError();
3448 }
3449
3450 return ipmi::responseSuccess();
3451}
3452
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003453using BasicVariantType =
3454 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3455 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3456 uint16_t, uint8_t, bool>;
3457using PropertyMapType =
3458 boost::container::flat_map<std::string, BasicVariantType>;
3459static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3460 "xyz.openbmc_project.Configuration.PSUPresence"};
3461int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3462 std::vector<uint64_t>& addrTable)
3463{
3464 boost::system::error_code ec;
3465 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3466 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3467 "/xyz/openbmc_project/object_mapper",
3468 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3469 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
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 for (const auto& object : subtree)
3477 {
3478 std::string pathName = object.first;
3479 for (const auto& serviceIface : object.second)
3480 {
3481 std::string serviceName = serviceIface.first;
3482
3483 ec.clear();
3484 PropertyMapType propMap =
3485 ctx->bus->yield_method_call<PropertyMapType>(
3486 ctx->yield, ec, serviceName, pathName,
3487 "org.freedesktop.DBus.Properties", "GetAll",
3488 "xyz.openbmc_project.Configuration.PSUPresence");
3489 if (ec)
3490 {
3491 phosphor::logging::log<phosphor::logging::level::ERR>(
3492 "Failed to set dbus property to cold redundancy");
3493 return -1;
3494 }
3495 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3496 auto psuAddress =
3497 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3498
3499 if (psuBus == nullptr || psuAddress == nullptr)
3500 {
3501 std::cerr << "error finding necessary "
3502 "entry in configuration\n";
3503 return -1;
3504 }
3505 bus = static_cast<uint8_t>(*psuBus);
3506 addrTable = *psuAddress;
3507 return 0;
3508 }
3509 }
3510 return -1;
3511}
3512
3513static const constexpr uint8_t addrOffset = 8;
3514static const constexpr uint8_t psuRevision = 0xd9;
3515static const constexpr uint8_t defaultPSUBus = 7;
3516// Second Minor, Primary Minor, Major
3517static const constexpr size_t verLen = 3;
3518ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3519{
3520 uint8_t bus = defaultPSUBus;
3521 std::vector<uint64_t> addrTable;
3522 std::vector<uint8_t> result;
3523 if (getPSUAddress(ctx, bus, addrTable))
3524 {
3525 std::cerr << "Failed to get PSU bus and address\n";
3526 return ipmi::responseResponseError();
3527 }
3528
3529 for (const auto& slaveAddr : addrTable)
3530 {
3531 std::vector<uint8_t> writeData = {psuRevision};
3532 std::vector<uint8_t> readBuf(verLen);
3533 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3534 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3535
3536 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3537 if (retI2C != ipmi::ccSuccess)
3538 {
3539 for (size_t idx = 0; idx < verLen; idx++)
3540 {
3541 result.emplace_back(0x00);
3542 }
3543 }
3544 else
3545 {
3546 for (const uint8_t& data : readBuf)
3547 {
3548 result.emplace_back(data);
3549 }
3550 }
3551 }
3552
3553 return ipmi::responseSuccess(result);
3554}
3555
srikanta mondal2030d7c2020-05-03 17:25:25 +00003556std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3557 const std::string& name)
3558{
3559 Value dbusValue = 0;
3560 std::string serviceName;
3561
3562 boost::system::error_code ec =
3563 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3564
3565 if (ec)
3566 {
3567 phosphor::logging::log<phosphor::logging::level::ERR>(
3568 "Failed to perform Multinode getService.");
3569 return std::nullopt;
3570 }
3571
3572 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3573 multiNodeIntf, name, dbusValue);
3574 if (ec)
3575 {
3576 phosphor::logging::log<phosphor::logging::level::ERR>(
3577 "Failed to perform Multinode get property");
3578 return std::nullopt;
3579 }
3580
3581 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3582 if (!multiNodeVal)
3583 {
3584 phosphor::logging::log<phosphor::logging::level::ERR>(
3585 "getMultiNodeInfoPresence: error to get multinode");
3586 return std::nullopt;
3587 }
3588 return *multiNodeVal;
3589}
3590
3591/** @brief implements OEM get reading command
3592 * @param domain ID
3593 * @param reading Type
3594 * - 00h = platform Power Consumption
3595 * - 01h = inlet Air Temp
3596 * - 02h = icc_TDC from PECI
3597 * @param reserved, write as 0000h
3598 *
3599 * @returns IPMI completion code plus response data
3600 * - response
3601 * - domain ID
3602 * - reading Type
3603 * - 00h = platform Power Consumption
3604 * - 01h = inlet Air Temp
3605 * - 02h = icc_TDC from PECI
3606 * - reading
3607 */
3608ipmi::RspType<uint4_t, // domain ID
3609 uint4_t, // reading Type
3610 uint16_t // reading Value
3611 >
3612 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3613 uint4_t readingType, uint16_t reserved)
3614{
3615 constexpr uint8_t platformPower = 0;
3616 constexpr uint8_t inletAirTemp = 1;
3617 constexpr uint8_t iccTdc = 2;
3618
3619 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3620 {
3621 return ipmi::responseInvalidFieldRequest();
3622 }
3623
3624 // This command should run only from multi-node product.
3625 // For all other platforms this command will return invalid.
3626
3627 std::optional<uint8_t> nodeInfo =
3628 getMultiNodeInfoPresence(ctx, "NodePresence");
3629 if (!nodeInfo || !*nodeInfo)
3630 {
3631 return ipmi::responseInvalidCommand();
3632 }
3633
3634 uint16_t oemReadingValue = 0;
3635 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3636 {
3637 double value = 0;
3638 boost::system::error_code ec = ipmi::getDbusProperty(
3639 ctx, "xyz.openbmc_project.HwmonTempSensor",
3640 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3641 "xyz.openbmc_project.Sensor.Value", "Value", value);
3642 if (ec)
3643 {
3644 phosphor::logging::log<phosphor::logging::level::ERR>(
3645 "Failed to get BMC Get OEM temperature",
3646 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3647 return ipmi::responseUnspecifiedError();
3648 }
3649 // Take the Inlet temperature
3650 oemReadingValue = static_cast<uint16_t>(value);
3651 }
3652 else
3653 {
3654 phosphor::logging::log<phosphor::logging::level::ERR>(
3655 "Currently Get OEM Reading support only for Inlet Air Temp");
3656 return ipmi::responseParmOutOfRange();
3657 }
3658 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3659}
3660
AppaRao Puli28972062019-11-11 02:04:45 +05303661/** @brief implements the maximum size of
3662 * bridgeable messages used between KCS and
3663 * IPMB interfacesget security mode command.
3664 *
3665 * @returns IPMI completion code with following data
3666 * - KCS Buffer Size (In multiples of four bytes)
3667 * - IPMB Buffer Size (In multiples of four bytes)
3668 **/
3669ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3670{
3671 // for now this is hard coded; really this number is dependent on
3672 // the BMC kcs driver as well as the host kcs driver....
3673 // we can't know the latter.
3674 uint8_t kcsMaxBufferSize = 63 / 4;
3675 uint8_t ipmbMaxBufferSize = 128 / 4;
3676
3677 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3678}
3679
Jason M. Bills64796042018-10-03 16:51:55 -07003680static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003681{
3682 phosphor::logging::log<phosphor::logging::level::INFO>(
3683 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003684 ipmiPrintAndRegister(intel::netFnGeneral,
3685 intel::general::cmdGetChassisIdentifier, NULL,
3686 ipmiOEMGetChassisIdentifier,
3687 PRIVILEGE_USER); // get chassis identifier
3688
3689 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3690 NULL, ipmiOEMSetSystemGUID,
3691 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003692
3693 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003694 registerHandler(prioOemBase, intel::netFnGeneral,
3695 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3696 ipmiOEMDisableBMCSystemReset);
3697
Jason M. Billsb02bf092019-08-15 13:01:56 -07003698 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003699 registerHandler(prioOemBase, intel::netFnGeneral,
3700 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3701 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003702
Vernon Mauery98bbf692019-09-16 11:14:59 -07003703 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3704 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003705
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003706 registerHandler(prioOemBase, intel::netFnGeneral,
3707 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3708 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003709
Vernon Mauery98bbf692019-09-16 11:14:59 -07003710 ipmiPrintAndRegister(intel::netFnGeneral,
3711 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3712 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303713
Vernon Mauery98bbf692019-09-16 11:14:59 -07003714 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3715 intel::general::cmdSendEmbeddedFWUpdStatus,
3716 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303717
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303718 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3719 Privilege::Admin, ipmiOEMSlotIpmb);
3720
Vernon Mauery98bbf692019-09-16 11:14:59 -07003721 ipmiPrintAndRegister(intel::netFnGeneral,
3722 intel::general::cmdSetPowerRestoreDelay, NULL,
3723 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3724
3725 ipmiPrintAndRegister(intel::netFnGeneral,
3726 intel::general::cmdGetPowerRestoreDelay, NULL,
3727 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3728
3729 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3730 intel::general::cmdSetOEMUser2Activation,
3731 Privilege::Callback, ipmiOEMSetUser2Activation);
3732
3733 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3734 intel::general::cmdSetSpecialUserPassword,
3735 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303736
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003737 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003738 registerHandler(prioOemBase, intel::netFnGeneral,
3739 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3740 ipmiOEMGetProcessorErrConfig);
3741
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003742 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003743 registerHandler(prioOemBase, intel::netFnGeneral,
3744 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3745 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003746
Vernon Mauery98bbf692019-09-16 11:14:59 -07003747 ipmiPrintAndRegister(intel::netFnGeneral,
3748 intel::general::cmdSetShutdownPolicy, NULL,
3749 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003750
Vernon Mauery98bbf692019-09-16 11:14:59 -07003751 ipmiPrintAndRegister(intel::netFnGeneral,
3752 intel::general::cmdGetShutdownPolicy, NULL,
3753 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003754
anil kumar appanaf945eee2019-09-25 23:29:11 +00003755 registerHandler(prioOemBase, intel::netFnGeneral,
3756 intel::general::cmdSetFanConfig, Privilege::User,
3757 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003758
Vernon Mauery98bbf692019-09-16 11:14:59 -07003759 registerHandler(prioOemBase, intel::netFnGeneral,
3760 intel::general::cmdGetFanConfig, Privilege::User,
3761 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003762
Vernon Mauery98bbf692019-09-16 11:14:59 -07003763 registerHandler(prioOemBase, intel::netFnGeneral,
3764 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3765 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003766
Vernon Mauery98bbf692019-09-16 11:14:59 -07003767 registerHandler(prioOemBase, intel::netFnGeneral,
3768 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3769 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003770
Vernon Mauery98bbf692019-09-16 11:14:59 -07003771 registerHandler(prioOemBase, intel::netFnGeneral,
3772 intel::general::cmdSetFscParameter, Privilege::User,
3773 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003774
Vernon Mauery98bbf692019-09-16 11:14:59 -07003775 registerHandler(prioOemBase, intel::netFnGeneral,
3776 intel::general::cmdGetFscParameter, Privilege::User,
3777 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303778
Vernon Mauery98bbf692019-09-16 11:14:59 -07003779 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3780 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3781 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003782
Vernon Mauery98bbf692019-09-16 11:14:59 -07003783 registerHandler(prioOemBase, intel::netFnGeneral,
3784 intel::general::cmdGetNmiStatus, Privilege::User,
3785 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003786
Vernon Mauery98bbf692019-09-16 11:14:59 -07003787 registerHandler(prioOemBase, intel::netFnGeneral,
3788 intel::general::cmdSetNmiStatus, Privilege::Operator,
3789 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003790
Vernon Mauery98bbf692019-09-16 11:14:59 -07003791 registerHandler(prioOemBase, intel::netFnGeneral,
3792 intel::general::cmdGetEfiBootOptions, Privilege::User,
3793 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003794
Vernon Mauery98bbf692019-09-16 11:14:59 -07003795 registerHandler(prioOemBase, intel::netFnGeneral,
3796 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3797 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303798
Vernon Mauery98bbf692019-09-16 11:14:59 -07003799 registerHandler(prioOemBase, intel::netFnGeneral,
3800 intel::general::cmdGetSecurityMode, Privilege::User,
3801 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303802
Vernon Mauery98bbf692019-09-16 11:14:59 -07003803 registerHandler(prioOemBase, intel::netFnGeneral,
3804 intel::general::cmdSetSecurityMode, Privilege::Admin,
3805 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003806
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003807 registerHandler(prioOemBase, intel::netFnGeneral,
3808 intel::general::cmdGetLEDStatus, Privilege::Admin,
3809 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003810
Vernon Mauery98bbf692019-09-16 11:14:59 -07003811 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3812 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3813 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3814
3815 registerHandler(prioOemBase, intel::netFnGeneral,
3816 intel::general::cmdSetFaultIndication, Privilege::Operator,
3817 ipmiOEMSetFaultIndication);
3818
3819 registerHandler(prioOemBase, intel::netFnGeneral,
3820 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3821 ipmiOEMSetCRConfig);
3822
3823 registerHandler(prioOemBase, intel::netFnGeneral,
3824 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3825 ipmiOEMGetCRConfig);
3826
3827 registerHandler(prioOemBase, intel::netFnGeneral,
3828 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003829 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003830
Vernon Mauery98bbf692019-09-16 11:14:59 -07003831 registerHandler(prioOemBase, intel::netFnGeneral,
3832 intel::general::cmdSetDimmOffset, Privilege::Operator,
3833 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003834
Vernon Mauery98bbf692019-09-16 11:14:59 -07003835 registerHandler(prioOemBase, intel::netFnGeneral,
3836 intel::general::cmdGetDimmOffset, Privilege::Operator,
3837 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003838
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003839 registerHandler(prioOemBase, intel::netFnGeneral,
3840 intel::general::cmdGetPSUVersion, Privilege::User,
3841 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303842
3843 registerHandler(prioOemBase, intel::netFnGeneral,
3844 intel::general::cmdGetBufferSize, Privilege::User,
3845 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00003846
3847 registerHandler(prioOemBase, intel::netFnGeneral,
3848 intel::general::cmdOEMGetReading, Privilege::User,
3849 ipmiOEMGetReading);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003850}
3851
3852} // namespace ipmi