blob: 46566a35c849165f5ddd7146446122f76060c83c [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;
744 uint2_t cpu1Status =
745 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
746 uint2_t cpu2Status =
747 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
748 uint2_t cpu3Status =
749 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
750 uint2_t cpu4Status =
751 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
752
753 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
754 try
755 {
756 auto service = ipmi::getService(*busp, processorErrConfigIntf,
757 processorErrConfigObjPath);
758
759 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
760 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
761 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
762 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
763 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
764 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
765 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
766 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
767 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
768 }
769 catch (const std::exception& e)
770 {
771 phosphor::logging::log<phosphor::logging::level::ERR>(
772 "Failed to fetch processor error config",
773 phosphor::logging::entry("ERROR=%s", e.what()));
774 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700775 }
776
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700777 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
778 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
779 cpu2Status, cpu3CATERRCount, cpu3Status,
780 cpu4CATERRCount, cpu4Status, crashdumpCount);
781}
Jason M. Bills64796042018-10-03 16:51:55 -0700782
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700783ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
784 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
785 std::optional<bool> clearCPUErrorCount,
786 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
787{
788 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700789
790 try
791 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700792 auto service = ipmi::getService(*busp, processorErrConfigIntf,
793 processorErrConfigObjPath);
794 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
795 processorErrConfigIntf, "ResetOnCATERR",
796 resetOnCATERR);
797 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
798 processorErrConfigIntf, "ResetOnERR2",
799 resetOnERR2);
800 if (clearCPUErrorCount.value_or(false))
801 {
802 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700803 processorErrConfigIntf, "ErrorCountCPU1",
804 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700805 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700806 processorErrConfigIntf, "ErrorCountCPU2",
807 static_cast<uint8_t>(0));
808 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
809 processorErrConfigIntf, "ErrorCountCPU3",
810 static_cast<uint8_t>(0));
811 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
812 processorErrConfigIntf, "ErrorCountCPU4",
813 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700814 }
815 if (clearCrashdumpCount.value_or(false))
816 {
817 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700818 processorErrConfigIntf, "CrashdumpCount",
819 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700820 }
Jason M. Bills64796042018-10-03 16:51:55 -0700821 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700822 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700823 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800824 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700825 "Failed to set processor error config",
826 phosphor::logging::entry("EXCEPTION=%s", e.what()));
827 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700828 }
829
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700830 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700831}
832
Yong Li703922d2018-11-06 13:25:31 +0800833ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
834 ipmi_request_t request,
835 ipmi_response_t response,
836 ipmi_data_len_t dataLen,
837 ipmi_context_t context)
838{
839 GetOEMShutdownPolicyRes* resp =
840 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
841
842 if (*dataLen != 0)
843 {
844 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800845 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800846 *dataLen = 0;
847 return IPMI_CC_REQ_DATA_LEN_INVALID;
848 }
849
850 *dataLen = 0;
851
852 try
853 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700854 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800855 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700856 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
857 Value variant = getDbusProperty(
858 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
859 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800860
861 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
862 convertPolicyFromString(std::get<std::string>(variant)) ==
863 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
864 NoShutdownOnOCOT)
865 {
866 resp->policy = 0;
867 }
868 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
869 convertPolicyFromString(std::get<std::string>(variant)) ==
870 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
871 Policy::ShutdownOnOCOT)
872 {
873 resp->policy = 1;
874 }
875 else
876 {
877 phosphor::logging::log<phosphor::logging::level::ERR>(
878 "oem_set_shutdown_policy: invalid property!",
879 phosphor::logging::entry(
880 "PROP=%s", std::get<std::string>(variant).c_str()));
881 return IPMI_CC_UNSPECIFIED_ERROR;
882 }
Yong Li703922d2018-11-06 13:25:31 +0800883 // TODO needs to check if it is multi-node products,
884 // policy is only supported on node 3/4
885 resp->policySupport = shutdownPolicySupported;
886 }
887 catch (sdbusplus::exception_t& e)
888 {
889 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
890 return IPMI_CC_UNSPECIFIED_ERROR;
891 }
892
893 *dataLen = sizeof(GetOEMShutdownPolicyRes);
894 return IPMI_CC_OK;
895}
896
897ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
898 ipmi_request_t request,
899 ipmi_response_t response,
900 ipmi_data_len_t dataLen,
901 ipmi_context_t context)
902{
903 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800904 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
905 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
906 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800907
908 // TODO needs to check if it is multi-node products,
909 // policy is only supported on node 3/4
910 if (*dataLen != 1)
911 {
912 phosphor::logging::log<phosphor::logging::level::ERR>(
913 "oem_set_shutdown_policy: invalid input len!");
914 *dataLen = 0;
915 return IPMI_CC_REQ_DATA_LEN_INVALID;
916 }
917
918 *dataLen = 0;
919 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
920 {
921 phosphor::logging::log<phosphor::logging::level::ERR>(
922 "oem_set_shutdown_policy: invalid input!");
923 return IPMI_CC_INVALID_FIELD_REQUEST;
924 }
925
Yong Li0669d192019-05-06 14:01:46 +0800926 if (*req == noShutdownOnOCOT)
927 {
928 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
929 Policy::NoShutdownOnOCOT;
930 }
931 else
932 {
933 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
934 Policy::ShutdownOnOCOT;
935 }
936
Yong Li703922d2018-11-06 13:25:31 +0800937 try
938 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700939 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800940 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700941 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800942 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700943 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800944 oemShutdownPolicyObjPathProp,
945 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800946 }
947 catch (sdbusplus::exception_t& e)
948 {
949 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
950 return IPMI_CC_UNSPECIFIED_ERROR;
951 }
952
953 return IPMI_CC_OK;
954}
955
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530956/** @brief implementation for check the DHCP or not in IPv4
957 * @param[in] Channel - Channel number
958 * @returns true or false.
959 */
960static bool isDHCPEnabled(uint8_t Channel)
961{
962 try
963 {
964 auto ethdevice = getChannelName(Channel);
965 if (ethdevice.empty())
966 {
967 return false;
968 }
969 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700970 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530971 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700972 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
973 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530974 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700975 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530976 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
977 {
978 return true;
979 }
980 else
981 {
982 return false;
983 }
984 }
985 catch (sdbusplus::exception_t& e)
986 {
987 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
988 return true;
989 }
990}
991
992/** @brief implementes for check the DHCP or not in IPv6
993 * @param[in] Channel - Channel number
994 * @returns true or false.
995 */
996static bool isDHCPIPv6Enabled(uint8_t Channel)
997{
998
999 try
1000 {
1001 auto ethdevice = getChannelName(Channel);
1002 if (ethdevice.empty())
1003 {
1004 return false;
1005 }
1006 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -07001007 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301008 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001009 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
1010 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301011 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001012 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301013 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
1014 {
1015 return true;
1016 }
1017 else
1018 {
1019 return false;
1020 }
1021 }
1022 catch (sdbusplus::exception_t& e)
1023 {
1024 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1025 return true;
1026 }
1027}
1028
1029/** @brief implementes the creating of default new user
1030 * @param[in] userName - new username in 16 bytes.
1031 * @param[in] userPassword - new password in 20 bytes
1032 * @returns ipmi completion code.
1033 */
1034ipmi::RspType<> ipmiOEMSetUser2Activation(
1035 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1036 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1037{
1038 bool userState = false;
1039 // Check for System Interface not exist and LAN should be static
1040 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1041 {
1042 ChannelInfo chInfo;
1043 try
1044 {
1045 getChannelInfo(channel, chInfo);
1046 }
1047 catch (sdbusplus::exception_t& e)
1048 {
1049 phosphor::logging::log<phosphor::logging::level::ERR>(
1050 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1051 phosphor::logging::entry("MSG: %s", e.description()));
1052 return ipmi::response(ipmi::ccUnspecifiedError);
1053 }
1054 if (chInfo.mediumType ==
1055 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1056 {
1057 phosphor::logging::log<phosphor::logging::level::ERR>(
1058 "ipmiOEMSetUser2Activation: system interface exist .");
1059 return ipmi::response(ipmi::ccCommandNotAvailable);
1060 }
1061 else
1062 {
1063
1064 if (chInfo.mediumType ==
1065 static_cast<uint8_t>(EChannelMediumType::lan8032))
1066 {
1067 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1068 {
1069 phosphor::logging::log<phosphor::logging::level::ERR>(
1070 "ipmiOEMSetUser2Activation: DHCP enabled .");
1071 return ipmi::response(ipmi::ccCommandNotAvailable);
1072 }
1073 }
1074 }
1075 }
1076 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1077 if (ipmi::ccSuccess ==
1078 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1079 {
1080 if (enabledUsers > 1)
1081 {
1082 phosphor::logging::log<phosphor::logging::level::ERR>(
1083 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1084 return ipmi::response(ipmi::ccCommandNotAvailable);
1085 }
1086 // Check the user 2 is enabled or not
1087 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1088 if (userState == true)
1089 {
1090 phosphor::logging::log<phosphor::logging::level::ERR>(
1091 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1092 return ipmi::response(ipmi::ccCommandNotAvailable);
1093 }
1094 }
1095 else
1096 {
1097 return ipmi::response(ipmi::ccUnspecifiedError);
1098 }
1099
1100#if BYTE_ORDER == LITTLE_ENDIAN
1101 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1102#endif
1103#if BYTE_ORDER == BIG_ENDIAN
1104 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1105#endif
1106
Vernon Mauery037cabd2020-05-14 12:16:01 -07001107 // ipmiUserSetUserName correctly handles char*, possibly non-null
1108 // terminated strings using ipmiMaxUserName size
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001109 size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()),
1110 sizeof(userName));
1111 const std::string userNameRaw(
1112 reinterpret_cast<const char*>(userName.data()), nameLen);
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001113
Vernon Mauery037cabd2020-05-14 12:16:01 -07001114 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301115 {
1116 if (ipmi::ccSuccess ==
1117 ipmiUserSetUserPassword(
1118 ipmiDefaultUserId,
1119 reinterpret_cast<const char*>(userPassword.data())))
1120 {
1121 if (ipmi::ccSuccess ==
1122 ipmiUserSetPrivilegeAccess(
1123 ipmiDefaultUserId,
1124 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1125 privAccess, true))
1126 {
1127 phosphor::logging::log<phosphor::logging::level::INFO>(
1128 "ipmiOEMSetUser2Activation: user created successfully ");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001129 OPENSSL_cleanse(userPassword.data(), userPassword.size());
1130
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301131 return ipmi::responseSuccess();
1132 }
1133 }
1134 // we need to delete the default user id which added in this command as
1135 // password / priv setting is failed.
Jayaprakash Mutyala3fbe8d22020-10-29 14:42:59 +00001136 ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>(""));
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301137 phosphor::logging::log<phosphor::logging::level::ERR>(
1138 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001139 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301140 }
1141 else
1142 {
1143 phosphor::logging::log<phosphor::logging::level::ERR>(
1144 "ipmiOEMSetUser2Activation: Setting username failed.");
1145 }
1146
1147 return ipmi::response(ipmi::ccCommandNotAvailable);
1148}
1149
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301150/** @brief implementes executing the linux command
1151 * @param[in] linux command
1152 * @returns status
1153 */
1154
1155static uint8_t executeCmd(const char* path)
1156{
1157 boost::process::child execProg(path);
1158 execProg.wait();
1159
1160 int retCode = execProg.exit_code();
1161 if (retCode)
1162 {
1163 return ipmi::ccUnspecifiedError;
1164 }
1165 return ipmi::ccSuccess;
1166}
1167
1168/** @brief implementes ASD Security event logging
1169 * @param[in] Event message string
1170 * @param[in] Event Severity
1171 * @returns status
1172 */
1173
1174static void atScaleDebugEventlog(std::string msg, int severity)
1175{
1176 std::string eventStr = "OpenBMC.0.1." + msg;
1177 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1178 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1179 eventStr.c_str(), NULL);
1180}
1181
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301182/** @brief implementes setting password for special user
1183 * @param[in] specialUserIndex
1184 * @param[in] userPassword - new password in 20 bytes
1185 * @returns ipmi completion code.
1186 */
1187ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1188 uint8_t specialUserIndex,
1189 std::vector<uint8_t> userPassword)
1190{
1191 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301192 ipmi_ret_t status = ipmi::ccSuccess;
1193
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301194 try
1195 {
1196 getChannelInfo(ctx->channel, chInfo);
1197 }
1198 catch (sdbusplus::exception_t& e)
1199 {
1200 phosphor::logging::log<phosphor::logging::level::ERR>(
1201 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1202 phosphor::logging::entry("MSG: %s", e.description()));
1203 return ipmi::responseUnspecifiedError();
1204 }
1205 if (chInfo.mediumType !=
1206 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1207 {
1208 phosphor::logging::log<phosphor::logging::level::ERR>(
1209 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1210 "interface");
1211 return ipmi::responseCommandNotAvailable();
1212 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301213
1214 // 0 for root user and 1 for AtScaleDebug is allowed
1215 if (specialUserIndex >
1216 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301217 {
1218 phosphor::logging::log<phosphor::logging::level::ERR>(
1219 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1220 return ipmi::responseParmOutOfRange();
1221 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301222 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301223 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301224 constexpr uint8_t minPasswordSizeRequired = 6;
1225 std::string passwd;
1226 if (userPassword.size() < minPasswordSizeRequired ||
1227 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1228 {
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001229 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301230 return ipmi::responseReqDataLenInvalid();
1231 }
1232 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1233 userPassword.size());
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001234 // Clear sensitive data
1235 OPENSSL_cleanse(userPassword.data(), userPassword.size());
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301236 if (specialUserIndex ==
1237 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1238 {
1239 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1240
1241 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1242 }
1243 else
1244 {
1245 status = ipmiSetSpecialUserPassword("root", passwd);
1246 }
Jayaprakash Mutyala94204162020-10-23 06:17:56 +00001247 // Clear sensitive data
1248 OPENSSL_cleanse(&passwd, passwd.length());
1249
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301250 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301251 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301252 else
1253 {
1254 if (specialUserIndex ==
1255 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1256 {
1257 status = executeCmd("passwd -d root");
1258 }
1259 else
1260 {
1261
1262 status = executeCmd("passwd -d asdbg");
1263
1264 if (status == 0)
1265 {
1266 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1267 LOG_INFO);
1268 }
1269 }
1270 return ipmi::response(status);
1271 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301272}
1273
Kuiying Wang45f04982018-12-26 09:23:08 +08001274namespace ledAction
1275{
1276using namespace sdbusplus::xyz::openbmc_project::Led::server;
1277std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001278 {Physical::Action::Off, 0},
1279 {Physical::Action::On, 2},
1280 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001281
1282std::map<uint8_t, std::string> offsetObjPath = {
1283 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1284
1285} // namespace ledAction
1286
1287int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1288 const std::string& objPath, uint8_t& state)
1289{
1290 try
1291 {
1292 std::string service = getService(bus, intf, objPath);
1293 Value stateValue =
1294 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001295 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001296 state = ledAction::actionDbusToIpmi.at(
1297 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1298 convertActionFromString(strState));
1299 }
1300 catch (sdbusplus::exception::SdBusError& e)
1301 {
1302 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1303 return -1;
1304 }
1305 return 0;
1306}
1307
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001308ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001309{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001310 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001311 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001312 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001313 for (auto it = ledAction::offsetObjPath.begin();
1314 it != ledAction::offsetObjPath.end(); ++it)
1315 {
1316 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001317 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001318 {
1319 phosphor::logging::log<phosphor::logging::level::ERR>(
1320 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001321 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001322 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001323 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001324 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001325 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001326}
1327
Yong Li23737fe2019-02-19 08:49:55 +08001328ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1329 ipmi_request_t request,
1330 ipmi_response_t response,
1331 ipmi_data_len_t dataLen,
1332 ipmi_context_t context)
1333{
1334 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1335 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1336
1337 if (*dataLen == 0)
1338 {
1339 phosphor::logging::log<phosphor::logging::level::ERR>(
1340 "CfgHostSerial: invalid input len!",
1341 phosphor::logging::entry("LEN=%d", *dataLen));
1342 return IPMI_CC_REQ_DATA_LEN_INVALID;
1343 }
1344
1345 switch (req->command)
1346 {
1347 case getHostSerialCfgCmd:
1348 {
1349 if (*dataLen != 1)
1350 {
1351 phosphor::logging::log<phosphor::logging::level::ERR>(
1352 "CfgHostSerial: invalid input len!");
1353 *dataLen = 0;
1354 return IPMI_CC_REQ_DATA_LEN_INVALID;
1355 }
1356
1357 *dataLen = 0;
1358
1359 boost::process::ipstream is;
1360 std::vector<std::string> data;
1361 std::string line;
1362 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1363 boost::process::std_out > is);
1364
1365 while (c1.running() && std::getline(is, line) && !line.empty())
1366 {
1367 data.push_back(line);
1368 }
1369
1370 c1.wait();
1371 if (c1.exit_code())
1372 {
1373 phosphor::logging::log<phosphor::logging::level::ERR>(
1374 "CfgHostSerial:: error on execute",
1375 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1376 // Using the default value
1377 *resp = 0;
1378 }
1379 else
1380 {
1381 if (data.size() != 1)
1382 {
1383 phosphor::logging::log<phosphor::logging::level::ERR>(
1384 "CfgHostSerial:: error on read env");
1385 return IPMI_CC_UNSPECIFIED_ERROR;
1386 }
1387 try
1388 {
1389 unsigned long tmp = std::stoul(data[0]);
1390 if (tmp > std::numeric_limits<uint8_t>::max())
1391 {
1392 throw std::out_of_range("Out of range");
1393 }
1394 *resp = static_cast<uint8_t>(tmp);
1395 }
1396 catch (const std::invalid_argument& e)
1397 {
1398 phosphor::logging::log<phosphor::logging::level::ERR>(
1399 "invalid config ",
1400 phosphor::logging::entry("ERR=%s", e.what()));
1401 return IPMI_CC_UNSPECIFIED_ERROR;
1402 }
1403 catch (const std::out_of_range& e)
1404 {
1405 phosphor::logging::log<phosphor::logging::level::ERR>(
1406 "out_of_range config ",
1407 phosphor::logging::entry("ERR=%s", e.what()));
1408 return IPMI_CC_UNSPECIFIED_ERROR;
1409 }
1410 }
1411
1412 *dataLen = 1;
1413 break;
1414 }
1415 case setHostSerialCfgCmd:
1416 {
1417 if (*dataLen != sizeof(CfgHostSerialReq))
1418 {
1419 phosphor::logging::log<phosphor::logging::level::ERR>(
1420 "CfgHostSerial: invalid input len!");
1421 *dataLen = 0;
1422 return IPMI_CC_REQ_DATA_LEN_INVALID;
1423 }
1424
1425 *dataLen = 0;
1426
1427 if (req->parameter > HostSerialCfgParamMax)
1428 {
1429 phosphor::logging::log<phosphor::logging::level::ERR>(
1430 "CfgHostSerial: invalid input!");
1431 return IPMI_CC_INVALID_FIELD_REQUEST;
1432 }
1433
1434 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1435 std::to_string(req->parameter));
1436
1437 c1.wait();
1438 if (c1.exit_code())
1439 {
1440 phosphor::logging::log<phosphor::logging::level::ERR>(
1441 "CfgHostSerial:: error on execute",
1442 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1443 return IPMI_CC_UNSPECIFIED_ERROR;
1444 }
1445 break;
1446 }
1447 default:
1448 phosphor::logging::log<phosphor::logging::level::ERR>(
1449 "CfgHostSerial: invalid input!");
1450 *dataLen = 0;
1451 return IPMI_CC_INVALID_FIELD_REQUEST;
1452 }
1453
1454 return IPMI_CC_OK;
1455}
1456
James Feist91244a62019-02-19 15:04:54 -08001457constexpr const char* thermalModeInterface =
1458 "xyz.openbmc_project.Control.ThermalMode";
1459constexpr const char* thermalModePath =
1460 "/xyz/openbmc_project/control/thermal_mode";
1461
1462bool getFanProfileInterface(
1463 sdbusplus::bus::bus& bus,
1464 boost::container::flat_map<
1465 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1466{
1467 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1468 "GetAll");
1469 call.append(thermalModeInterface);
1470 try
1471 {
1472 auto data = bus.call(call);
1473 data.read(resp);
1474 }
1475 catch (sdbusplus::exception_t& e)
1476 {
1477 phosphor::logging::log<phosphor::logging::level::ERR>(
1478 "getFanProfileInterface: can't get thermal mode!",
1479 phosphor::logging::entry("ERR=%s", e.what()));
1480 return false;
1481 }
1482 return true;
1483}
1484
anil kumar appanaf945eee2019-09-25 23:29:11 +00001485/**@brief implements the OEM set fan config.
1486 * @param selectedFanProfile - fan profile to enable
1487 * @param reserved1
1488 * @param performanceMode - Performance/Acoustic mode
1489 * @param reserved2
1490 * @param setPerformanceMode - set Performance/Acoustic mode
1491 * @param setFanProfile - set fan profile
1492 *
1493 * @return IPMI completion code.
1494 **/
1495ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1496
1497 uint2_t reserved1, bool performanceMode,
1498 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301499 bool setFanProfile,
1500 std::optional<uint8_t> dimmGroupId,
1501 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001502{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001503 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001504 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001505 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001506 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301507
1508 if (dimmGroupId)
1509 {
1510 if (*dimmGroupId >= maxCPUNum)
1511 {
1512 return ipmi::responseInvalidFieldRequest();
1513 }
1514 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1515 {
1516 return ipmi::responseInvalidFieldRequest();
1517 }
1518 }
1519
James Feist91244a62019-02-19 15:04:54 -08001520 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001521 boost::container::flat_map<
1522 std::string, std::variant<std::vector<std::string>, std::string>>
1523 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001524 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1525 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001526 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001527 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001528 }
1529
1530 std::vector<std::string>* supported =
1531 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1532 if (supported == nullptr)
1533 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001534 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001535 }
1536 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001537 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001538 {
James Feist91244a62019-02-19 15:04:54 -08001539 if (performanceMode)
1540 {
1541
1542 if (std::find(supported->begin(), supported->end(),
1543 "Performance") != supported->end())
1544 {
1545 mode = "Performance";
1546 }
1547 }
1548 else
1549 {
James Feist91244a62019-02-19 15:04:54 -08001550 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1551 supported->end())
1552 {
1553 mode = "Acoustic";
1554 }
1555 }
1556 if (mode.empty())
1557 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001558 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001559 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001560
1561 try
1562 {
1563 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1564 thermalModeInterface, "Current", mode);
1565 }
1566 catch (sdbusplus::exception_t& e)
1567 {
1568 phosphor::logging::log<phosphor::logging::level::ERR>(
1569 "ipmiOEMSetFanConfig: can't set thermal mode!",
1570 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1571 return ipmi::responseResponseError();
1572 }
James Feist91244a62019-02-19 15:04:54 -08001573 }
1574
anil kumar appanaf945eee2019-09-25 23:29:11 +00001575 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001576}
1577
James Feist5b693632019-07-09 09:06:09 -07001578ipmi::RspType<uint8_t, // profile support map
1579 uint8_t, // fan control profile enable
1580 uint8_t, // flags
1581 uint32_t // dimm presence bit map
1582 >
1583 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001584{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301585 if (dimmGroupId >= maxCPUNum)
1586 {
1587 return ipmi::responseInvalidFieldRequest();
1588 }
1589
1590 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1591
1592 if (!cpuStatus)
1593 {
1594 return ipmi::responseInvalidFieldRequest();
1595 }
1596
James Feist91244a62019-02-19 15:04:54 -08001597 boost::container::flat_map<
1598 std::string, std::variant<std::vector<std::string>, std::string>>
1599 profileData;
1600
Vernon Mauery15419dd2019-05-24 09:40:30 -07001601 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1602 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001603 {
James Feist5b693632019-07-09 09:06:09 -07001604 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001605 }
1606
1607 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1608
1609 if (current == nullptr)
1610 {
1611 phosphor::logging::log<phosphor::logging::level::ERR>(
1612 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001613 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001614 }
1615 bool performance = (*current == "Performance");
1616
James Feist5b693632019-07-09 09:06:09 -07001617 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001618 if (performance)
1619 {
James Feist5b693632019-07-09 09:06:09 -07001620 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001621 }
1622
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001623 constexpr uint8_t fanControlDefaultProfile = 0x80;
1624 constexpr uint8_t fanControlProfileState = 0x00;
1625 constexpr uint32_t dimmPresenceBitmap = 0x00;
1626
1627 return ipmi::responseSuccess(fanControlDefaultProfile,
1628 fanControlProfileState, flags,
1629 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001630}
James Feist5f957ca2019-03-14 15:33:55 -07001631constexpr const char* cfmLimitSettingPath =
1632 "/xyz/openbmc_project/control/cfm_limit";
1633constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001634constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001635constexpr const size_t legacyPCHSensorNumber = 0x22;
1636constexpr const char* exitAirPathName = "Exit_Air";
1637constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001638constexpr const char* pidConfigurationIface =
1639 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001640
James Feist09f6b602019-08-08 11:30:03 -07001641static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001642{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001643 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001644 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001645 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1646 "/xyz/openbmc_project/object_mapper",
1647 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001648
James Feistacc8a4e2019-04-02 14:23:57 -07001649 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001650 std::string path;
1651 GetSubTreeType resp;
1652 try
1653 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001654 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001655 reply.read(resp);
1656 }
1657 catch (sdbusplus::exception_t&)
1658 {
1659 phosphor::logging::log<phosphor::logging::level::ERR>(
1660 "ipmiOEMGetFscParameter: mapper error");
1661 };
James Feist09f6b602019-08-08 11:30:03 -07001662 auto config =
1663 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1664 return pair.first.find(name) != std::string::npos;
1665 });
James Feistfaa4f222019-03-21 16:21:55 -07001666 if (config != resp.end())
1667 {
1668 path = std::move(config->first);
1669 }
1670 return path;
1671}
James Feist5f957ca2019-03-14 15:33:55 -07001672
James Feistacc8a4e2019-04-02 14:23:57 -07001673// flat map to make alphabetical
1674static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1675{
1676 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001677 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001678 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001679 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1680 "/xyz/openbmc_project/object_mapper",
1681 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001682
1683 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1684 GetSubTreeType resp;
1685
1686 try
1687 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001688 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001689 reply.read(resp);
1690 }
1691 catch (sdbusplus::exception_t&)
1692 {
1693 phosphor::logging::log<phosphor::logging::level::ERR>(
1694 "getFanConfigPaths: mapper error");
1695 };
1696 for (const auto& [path, objects] : resp)
1697 {
1698 if (objects.empty())
1699 {
1700 continue; // should be impossible
1701 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001702
1703 try
1704 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001705 ret.emplace(path,
1706 getAllDbusProperties(*dbus, objects[0].first, path,
1707 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001708 }
1709 catch (sdbusplus::exception_t& e)
1710 {
1711 phosphor::logging::log<phosphor::logging::level::ERR>(
1712 "getPidConfigs: can't get DbusProperties!",
1713 phosphor::logging::entry("ERR=%s", e.what()));
1714 }
James Feistacc8a4e2019-04-02 14:23:57 -07001715 }
1716 return ret;
1717}
1718
1719ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1720{
1721 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1722 if (data.empty())
1723 {
1724 return ipmi::responseResponseError();
1725 }
1726 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1727 for (const auto& [_, pid] : data)
1728 {
1729 auto findClass = pid.find("Class");
1730 if (findClass == pid.end())
1731 {
1732 phosphor::logging::log<phosphor::logging::level::ERR>(
1733 "ipmiOEMGetFscParameter: found illegal pid "
1734 "configurations");
1735 return ipmi::responseResponseError();
1736 }
1737 std::string type = std::get<std::string>(findClass->second);
1738 if (type == "fan")
1739 {
1740 auto findOutLimit = pid.find("OutLimitMin");
1741 if (findOutLimit == pid.end())
1742 {
1743 phosphor::logging::log<phosphor::logging::level::ERR>(
1744 "ipmiOEMGetFscParameter: found illegal pid "
1745 "configurations");
1746 return ipmi::responseResponseError();
1747 }
1748 // get the min out of all the offsets
1749 minOffset = std::min(
1750 minOffset,
1751 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1752 }
1753 }
1754 if (minOffset == std::numeric_limits<uint8_t>::max())
1755 {
1756 phosphor::logging::log<phosphor::logging::level::ERR>(
1757 "ipmiOEMGetFscParameter: found no fan configurations!");
1758 return ipmi::responseResponseError();
1759 }
1760
1761 return ipmi::responseSuccess(minOffset);
1762}
1763
1764ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1765{
1766 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1767 if (data.empty())
1768 {
1769
1770 phosphor::logging::log<phosphor::logging::level::ERR>(
1771 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1772 return ipmi::responseResponseError();
1773 }
1774
Vernon Mauery15419dd2019-05-24 09:40:30 -07001775 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001776 bool found = false;
1777 for (const auto& [path, pid] : data)
1778 {
1779 auto findClass = pid.find("Class");
1780 if (findClass == pid.end())
1781 {
1782
1783 phosphor::logging::log<phosphor::logging::level::ERR>(
1784 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1785 "configurations");
1786 return ipmi::responseResponseError();
1787 }
1788 std::string type = std::get<std::string>(findClass->second);
1789 if (type == "fan")
1790 {
1791 auto findOutLimit = pid.find("OutLimitMin");
1792 if (findOutLimit == pid.end())
1793 {
1794
1795 phosphor::logging::log<phosphor::logging::level::ERR>(
1796 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1797 "configurations");
1798 return ipmi::responseResponseError();
1799 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001800 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001801 path, pidConfigurationIface, "OutLimitMin",
1802 static_cast<double>(offset));
1803 found = true;
1804 }
1805 }
1806 if (!found)
1807 {
1808 phosphor::logging::log<phosphor::logging::level::ERR>(
1809 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1810 return ipmi::responseResponseError();
1811 }
1812
1813 return ipmi::responseSuccess();
1814}
1815
1816ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1817 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001818{
1819 constexpr const size_t disableLimiting = 0x0;
1820
Vernon Mauery15419dd2019-05-24 09:40:30 -07001821 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001822 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001823 {
James Feist09f6b602019-08-08 11:30:03 -07001824 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001825 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001826 {
James Feist09f6b602019-08-08 11:30:03 -07001827 pathName = exitAirPathName;
1828 }
1829 else if (param1 == legacyPCHSensorNumber)
1830 {
1831 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001832 }
1833 else
1834 {
James Feistacc8a4e2019-04-02 14:23:57 -07001835 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001836 }
James Feist09f6b602019-08-08 11:30:03 -07001837 std::string path = getConfigPath(pathName);
1838 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1839 pidConfigurationIface, "SetPoint",
1840 static_cast<double>(param2));
1841 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001842 }
James Feistacc8a4e2019-04-02 14:23:57 -07001843 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001844 {
James Feistacc8a4e2019-04-02 14:23:57 -07001845 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001846
1847 // must be greater than 50 based on eps
1848 if (cfm < 50 && cfm != disableLimiting)
1849 {
James Feistacc8a4e2019-04-02 14:23:57 -07001850 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001851 }
1852
1853 try
1854 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001855 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001856 cfmLimitIface, "Limit",
1857 static_cast<double>(cfm));
1858 }
1859 catch (sdbusplus::exception_t& e)
1860 {
1861 phosphor::logging::log<phosphor::logging::level::ERR>(
1862 "ipmiOEMSetFscParameter: can't set cfm setting!",
1863 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001864 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001865 }
James Feistacc8a4e2019-04-02 14:23:57 -07001866 return ipmi::responseSuccess();
1867 }
1868 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1869 {
1870 constexpr const size_t maxDomainCount = 8;
1871 uint8_t requestedDomainMask = param1;
1872 boost::container::flat_map data = getPidConfigs();
1873 if (data.empty())
1874 {
1875
1876 phosphor::logging::log<phosphor::logging::level::ERR>(
1877 "ipmiOEMSetFscParameter: found no pid configurations!");
1878 return ipmi::responseResponseError();
1879 }
1880 size_t count = 0;
1881 for (const auto& [path, pid] : data)
1882 {
1883 auto findClass = pid.find("Class");
1884 if (findClass == pid.end())
1885 {
1886
1887 phosphor::logging::log<phosphor::logging::level::ERR>(
1888 "ipmiOEMSetFscParameter: found illegal pid "
1889 "configurations");
1890 return ipmi::responseResponseError();
1891 }
1892 std::string type = std::get<std::string>(findClass->second);
1893 if (type == "fan")
1894 {
1895 if (requestedDomainMask & (1 << count))
1896 {
1897 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001898 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001899 pidConfigurationIface, "OutLimitMax",
1900 static_cast<double>(param2));
1901 }
1902 count++;
1903 }
1904 }
1905 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001906 }
1907 else
1908 {
1909 // todo other command parts possibly
1910 // tcontrol is handled in peci now
1911 // fan speed offset not implemented yet
1912 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001913 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001914 }
1915}
1916
James Feistacc8a4e2019-04-02 14:23:57 -07001917ipmi::RspType<
1918 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1919 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001920{
James Feist09f6b602019-08-08 11:30:03 -07001921 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001922
Vernon Mauery15419dd2019-05-24 09:40:30 -07001923 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001924 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001925 {
James Feistacc8a4e2019-04-02 14:23:57 -07001926 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001927 {
James Feistacc8a4e2019-04-02 14:23:57 -07001928 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001929 }
1930
James Feist09f6b602019-08-08 11:30:03 -07001931 std::string pathName;
1932
1933 if (*param == legacyExitAirSensorNumber)
1934 {
1935 pathName = exitAirPathName;
1936 }
1937 else if (*param == legacyPCHSensorNumber)
1938 {
1939 pathName = pchPathName;
1940 }
1941 else
James Feistfaa4f222019-03-21 16:21:55 -07001942 {
James Feistacc8a4e2019-04-02 14:23:57 -07001943 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001944 }
James Feist09f6b602019-08-08 11:30:03 -07001945
1946 uint8_t setpoint = legacyDefaultSetpoint;
1947 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001948 if (path.size())
1949 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001950 Value val = ipmi::getDbusProperty(
1951 *dbus, "xyz.openbmc_project.EntityManager", path,
1952 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001953 setpoint = std::floor(std::get<double>(val) + 0.5);
1954 }
1955
1956 // old implementation used to return the "default" and current, we
1957 // don't make the default readily available so just make both the
1958 // same
James Feistfaa4f222019-03-21 16:21:55 -07001959
James Feistacc8a4e2019-04-02 14:23:57 -07001960 return ipmi::responseSuccess(
1961 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001962 }
James Feistacc8a4e2019-04-02 14:23:57 -07001963 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1964 {
1965 constexpr const size_t maxDomainCount = 8;
1966
1967 if (!param)
1968 {
1969 return ipmi::responseReqDataLenInvalid();
1970 }
1971 uint8_t requestedDomain = *param;
1972 if (requestedDomain >= maxDomainCount)
1973 {
1974 return ipmi::responseInvalidFieldRequest();
1975 }
1976
1977 boost::container::flat_map data = getPidConfigs();
1978 if (data.empty())
1979 {
1980 phosphor::logging::log<phosphor::logging::level::ERR>(
1981 "ipmiOEMGetFscParameter: found no pid configurations!");
1982 return ipmi::responseResponseError();
1983 }
1984 size_t count = 0;
1985 for (const auto& [_, pid] : data)
1986 {
1987 auto findClass = pid.find("Class");
1988 if (findClass == pid.end())
1989 {
1990 phosphor::logging::log<phosphor::logging::level::ERR>(
1991 "ipmiOEMGetFscParameter: found illegal pid "
1992 "configurations");
1993 return ipmi::responseResponseError();
1994 }
1995 std::string type = std::get<std::string>(findClass->second);
1996 if (type == "fan")
1997 {
1998 if (requestedDomain == count)
1999 {
2000 auto findOutLimit = pid.find("OutLimitMax");
2001 if (findOutLimit == pid.end())
2002 {
2003 phosphor::logging::log<phosphor::logging::level::ERR>(
2004 "ipmiOEMGetFscParameter: found illegal pid "
2005 "configurations");
2006 return ipmi::responseResponseError();
2007 }
2008
2009 return ipmi::responseSuccess(
2010 static_cast<uint8_t>(std::floor(
2011 std::get<double>(findOutLimit->second) + 0.5)));
2012 }
2013 else
2014 {
2015 count++;
2016 }
2017 }
2018 }
2019
2020 return ipmi::responseInvalidFieldRequest();
2021 }
2022 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07002023 {
2024
2025 /*
2026 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07002027 previous behavior didn't seem to prevent this, ignore the check for
2028 now.
James Feist5f957ca2019-03-14 15:33:55 -07002029
James Feistacc8a4e2019-04-02 14:23:57 -07002030 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002031 {
2032 phosphor::logging::log<phosphor::logging::level::ERR>(
2033 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002034 return IPMI_CC_REQ_DATA_LEN_INVALID;
2035 }
2036 */
2037 Value cfmLimit;
2038 Value cfmMaximum;
2039 try
2040 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002041 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002042 cfmLimitSettingPath, cfmLimitIface,
2043 "Limit");
2044 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002045 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002046 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2047 }
2048 catch (sdbusplus::exception_t& e)
2049 {
2050 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002051 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002052 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002053 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002054 }
2055
James Feistacc8a4e2019-04-02 14:23:57 -07002056 double cfmMax = std::get<double>(cfmMaximum);
2057 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002058
James Feistacc8a4e2019-04-02 14:23:57 -07002059 cfmLim = std::floor(cfmLim + 0.5);
2060 cfmMax = std::floor(cfmMax + 0.5);
2061 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2062 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002063
James Feistacc8a4e2019-04-02 14:23:57 -07002064 return ipmi::responseSuccess(
2065 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002066 }
James Feistacc8a4e2019-04-02 14:23:57 -07002067
James Feist5f957ca2019-03-14 15:33:55 -07002068 else
2069 {
2070 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002071 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002072 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002073 }
2074}
2075
Cheng C Yang773703a2019-08-15 09:41:11 +08002076using crConfigVariant =
2077 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2078
2079int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2080 const crConfigVariant& value,
2081 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2082{
2083 boost::system::error_code ec;
2084 ctx->bus->yield_method_call<void>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002085 ctx->yield, ec, "xyz.openbmc_project.PSURedundancy",
Cheng C Yang773703a2019-08-15 09:41:11 +08002086 "/xyz/openbmc_project/control/power_supply_redundancy",
2087 "org.freedesktop.DBus.Properties", "Set",
2088 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2089 if (ec)
2090 {
2091 phosphor::logging::log<phosphor::logging::level::ERR>(
2092 "Failed to set dbus property to cold redundancy");
2093 return -1;
2094 }
2095
2096 return 0;
2097}
2098
Kuiying Wange45333a2020-07-22 22:06:37 +08002099int getCRConfig(
2100 ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value,
2101 const std::string& service = "xyz.openbmc_project.PSURedundancy",
2102 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
Cheng C Yang773703a2019-08-15 09:41:11 +08002103{
2104 boost::system::error_code ec;
2105 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002106 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002107 "/xyz/openbmc_project/control/power_supply_redundancy",
2108 "org.freedesktop.DBus.Properties", "Get",
2109 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2110 if (ec)
2111 {
2112 phosphor::logging::log<phosphor::logging::level::ERR>(
2113 "Failed to get dbus property to cold redundancy");
2114 return -1;
2115 }
2116 return 0;
2117}
2118
2119uint8_t getPSUCount(void)
2120{
2121 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2122 ipmi::Value num;
2123 try
2124 {
2125 num = ipmi::getDbusProperty(
2126 *dbus, "xyz.openbmc_project.PSURedundancy",
2127 "/xyz/openbmc_project/control/power_supply_redundancy",
2128 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2129 }
2130 catch (sdbusplus::exception_t& e)
2131 {
2132 phosphor::logging::log<phosphor::logging::level::ERR>(
2133 "Failed to get PSUNumber property from dbus interface");
2134 return 0;
2135 }
2136 uint8_t* pNum = std::get_if<uint8_t>(&num);
2137 if (!pNum)
2138 {
2139 phosphor::logging::log<phosphor::logging::level::ERR>(
2140 "Error to get PSU Number");
2141 return 0;
2142 }
2143 return *pNum;
2144}
2145
2146bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2147{
2148 if (conf.size() < num)
2149 {
2150 phosphor::logging::log<phosphor::logging::level::ERR>(
2151 "Invalid PSU Ranking");
2152 return false;
2153 }
2154 std::set<uint8_t> confSet;
2155 for (uint8_t i = 0; i < num; i++)
2156 {
2157 if (conf[i] > num)
2158 {
2159 phosphor::logging::log<phosphor::logging::level::ERR>(
2160 "PSU Ranking is larger than current PSU number");
2161 return false;
2162 }
2163 confSet.emplace(conf[i]);
2164 }
2165
2166 if (confSet.size() != num)
2167 {
2168 phosphor::logging::log<phosphor::logging::level::ERR>(
2169 "duplicate PSU Ranking");
2170 return false;
2171 }
2172 return true;
2173}
2174
2175enum class crParameter
2176{
2177 crStatus = 0,
2178 crFeature = 1,
2179 rotationFeature = 2,
2180 rotationAlgo = 3,
2181 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002182 numOfPSU = 5,
2183 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002184};
2185
2186constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2187static const constexpr uint32_t oneDay = 0x15180;
2188static const constexpr uint32_t oneMonth = 0xf53700;
2189static const constexpr uint8_t userSpecific = 0x01;
2190static const constexpr uint8_t crSetCompleted = 0;
2191ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2192 uint8_t parameter,
2193 ipmi::message::Payload& payload)
2194{
2195 switch (static_cast<crParameter>(parameter))
2196 {
Cheng C Yang773703a2019-08-15 09:41:11 +08002197 case crParameter::rotationFeature:
2198 {
2199 uint8_t param1;
2200 if (payload.unpack(param1) || !payload.fullyUnpacked())
2201 {
2202 return ipmi::responseReqDataLenInvalid();
2203 }
2204 // Rotation Enable can only be true or false
2205 if (param1 > 1)
2206 {
2207 return ipmi::responseInvalidFieldRequest();
2208 }
2209 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2210 {
2211 return ipmi::responseResponseError();
2212 }
2213 break;
2214 }
2215 case crParameter::rotationAlgo:
2216 {
2217 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2218 std::string algoName;
2219 uint8_t param1;
2220 if (payload.unpack(param1))
2221 {
2222 return ipmi::responseReqDataLenInvalid();
2223 }
2224 switch (param1)
2225 {
2226 case 0:
2227 algoName = "xyz.openbmc_project.Control."
2228 "PowerSupplyRedundancy.Algo.bmcSpecific";
2229 break;
2230 case 1:
2231 algoName = "xyz.openbmc_project.Control."
2232 "PowerSupplyRedundancy.Algo.userSpecific";
2233 break;
2234 default:
2235 return ipmi::responseInvalidFieldRequest();
2236 }
2237 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2238 {
2239 return ipmi::responseResponseError();
2240 }
2241
2242 uint8_t numberOfPSU = getPSUCount();
2243 if (!numberOfPSU)
2244 {
2245 return ipmi::responseResponseError();
2246 }
2247 std::vector<uint8_t> rankOrder;
2248
2249 if (param1 == userSpecific)
2250 {
2251 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2252 {
2253 ipmi::responseReqDataLenInvalid();
2254 }
Yong Li83315132019-10-23 17:42:24 +08002255 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002256 {
2257 return ipmi::responseReqDataLenInvalid();
2258 }
2259
2260 if (!validateCRAlgo(rankOrder, numberOfPSU))
2261 {
2262 return ipmi::responseInvalidFieldRequest();
2263 }
2264 }
2265 else
2266 {
2267 if (rankOrder.size() > 0)
2268 {
2269 return ipmi::responseReqDataLenInvalid();
2270 }
2271 for (uint8_t i = 1; i <= numberOfPSU; i++)
2272 {
2273 rankOrder.emplace_back(i);
2274 }
2275 }
2276 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2277 {
2278 return ipmi::responseResponseError();
2279 }
2280 break;
2281 }
2282 case crParameter::rotationPeriod:
2283 {
2284 // Minimum Rotation period is One day (86400 seconds) and Max
2285 // Rotation Period is 6 month (0xf53700 seconds)
2286 uint32_t period;
2287 if (payload.unpack(period) || !payload.fullyUnpacked())
2288 {
2289 return ipmi::responseReqDataLenInvalid();
2290 }
2291 if ((period < oneDay) || (period > oneMonth))
2292 {
2293 return ipmi::responseInvalidFieldRequest();
2294 }
2295 if (setCRConfig(ctx, "PeriodOfRotation", period))
2296 {
2297 return ipmi::responseResponseError();
2298 }
2299 break;
2300 }
2301 default:
2302 {
2303 return ipmi::response(ccParameterNotSupported);
2304 }
2305 }
2306
Cheng C Yang773703a2019-08-15 09:41:11 +08002307 return ipmi::responseSuccess(crSetCompleted);
2308}
2309
Yong Li83315132019-10-23 17:42:24 +08002310ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002311 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2312{
2313 crConfigVariant value;
2314 switch (static_cast<crParameter>(parameter))
2315 {
2316 case crParameter::crStatus:
2317 {
2318 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2319 {
2320 return ipmi::responseResponseError();
2321 }
2322 std::string* pStatus = std::get_if<std::string>(&value);
2323 if (!pStatus)
2324 {
2325 phosphor::logging::log<phosphor::logging::level::ERR>(
2326 "Error to get ColdRedundancyStatus property");
2327 return ipmi::responseResponseError();
2328 }
2329 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2330 auto status =
2331 server::PowerSupplyRedundancy::convertStatusFromString(
2332 *pStatus);
2333 switch (status)
2334 {
2335 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002336 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002337 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002338
2339 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002340 return ipmi::responseSuccess(parameter,
Kuiying Wange45333a2020-07-22 22:06:37 +08002341 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002342 default:
2343 phosphor::logging::log<phosphor::logging::level::ERR>(
2344 "Error to get valid status");
2345 return ipmi::responseResponseError();
2346 }
2347 }
2348 case crParameter::crFeature:
2349 {
Kuiying Wange45333a2020-07-22 22:06:37 +08002350 if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value))
Cheng C Yang773703a2019-08-15 09:41:11 +08002351 {
2352 return ipmi::responseResponseError();
2353 }
2354 bool* pResponse = std::get_if<bool>(&value);
2355 if (!pResponse)
2356 {
2357 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wange45333a2020-07-22 22:06:37 +08002358 "Error to get PowerSupplyRedundancyEnabled property");
Cheng C Yang773703a2019-08-15 09:41:11 +08002359 return ipmi::responseResponseError();
2360 }
2361
Cheng C Yangf41e3342019-09-10 04:47:23 +08002362 return ipmi::responseSuccess(parameter,
2363 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002364 }
2365 case crParameter::rotationFeature:
2366 {
2367 if (getCRConfig(ctx, "RotationEnabled", value))
2368 {
2369 return ipmi::responseResponseError();
2370 }
2371 bool* pResponse = std::get_if<bool>(&value);
2372 if (!pResponse)
2373 {
2374 phosphor::logging::log<phosphor::logging::level::ERR>(
2375 "Error to get RotationEnabled property");
2376 return ipmi::responseResponseError();
2377 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002378 return ipmi::responseSuccess(parameter,
2379 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002380 }
2381 case crParameter::rotationAlgo:
2382 {
2383 if (getCRConfig(ctx, "RotationAlgorithm", value))
2384 {
2385 return ipmi::responseResponseError();
2386 }
2387
2388 std::string* pAlgo = std::get_if<std::string>(&value);
2389 if (!pAlgo)
2390 {
2391 phosphor::logging::log<phosphor::logging::level::ERR>(
2392 "Error to get RotationAlgorithm property");
2393 return ipmi::responseResponseError();
2394 }
Yong Li83315132019-10-23 17:42:24 +08002395 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002396 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2397 auto algo =
2398 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002399
Cheng C Yang773703a2019-08-15 09:41:11 +08002400 switch (algo)
2401 {
2402 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002403 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002404 break;
2405 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002406 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002407 break;
2408 default:
2409 phosphor::logging::log<phosphor::logging::level::ERR>(
2410 "Error to get valid algo");
2411 return ipmi::responseResponseError();
2412 }
2413
2414 if (getCRConfig(ctx, "RotationRankOrder", value))
2415 {
2416 return ipmi::responseResponseError();
2417 }
2418 std::vector<uint8_t>* pResponse =
2419 std::get_if<std::vector<uint8_t>>(&value);
2420 if (!pResponse)
2421 {
2422 phosphor::logging::log<phosphor::logging::level::ERR>(
2423 "Error to get RotationRankOrder property");
2424 return ipmi::responseResponseError();
2425 }
Yong Li83315132019-10-23 17:42:24 +08002426
Cheng C Yang773703a2019-08-15 09:41:11 +08002427 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002428 std::back_inserter(response));
2429
Cheng C Yangf41e3342019-09-10 04:47:23 +08002430 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002431 }
2432 case crParameter::rotationPeriod:
2433 {
2434 if (getCRConfig(ctx, "PeriodOfRotation", value))
2435 {
2436 return ipmi::responseResponseError();
2437 }
2438 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2439 if (!pResponse)
2440 {
2441 phosphor::logging::log<phosphor::logging::level::ERR>(
2442 "Error to get RotationAlgorithm property");
2443 return ipmi::responseResponseError();
2444 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002445 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002446 }
2447 case crParameter::numOfPSU:
2448 {
2449 uint8_t numberOfPSU = getPSUCount();
2450 if (!numberOfPSU)
2451 {
2452 return ipmi::responseResponseError();
2453 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002454 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002455 }
Yong Li19445ab2019-12-20 18:25:29 +08002456 case crParameter::rotationRankOrderEffective:
2457 {
2458 if (getCRConfig(ctx, "RotationRankOrder", value,
2459 "xyz.openbmc_project.PSURedundancy"))
2460 {
2461 return ipmi::responseResponseError();
2462 }
2463 std::vector<uint8_t>* pResponse =
2464 std::get_if<std::vector<uint8_t>>(&value);
2465 if (!pResponse)
2466 {
2467 phosphor::logging::log<phosphor::logging::level::ERR>(
2468 "Error to get effective RotationRankOrder property");
2469 return ipmi::responseResponseError();
2470 }
2471 return ipmi::responseSuccess(parameter, *pResponse);
2472 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002473 default:
2474 {
2475 return ipmi::response(ccParameterNotSupported);
2476 }
2477 }
2478}
2479
Zhu, Yungebe560b02019-04-21 21:19:21 -04002480ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2481 uint8_t faultState,
2482 uint8_t faultGroup,
2483 std::array<uint8_t, 8>& ledStateData)
2484{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002485 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2486 static const std::array<std::string, maxFaultType> faultNames = {
2487 "faultFan", "faultTemp", "faultPower",
2488 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002489
2490 constexpr uint8_t maxFaultSource = 0x4;
2491 constexpr uint8_t skipLEDs = 0xFF;
2492 constexpr uint8_t pinSize = 64;
2493 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002494 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002495
Zhikui Rence4e73f2019-12-06 13:59:47 -08002496 // same pin names need to be defined in dts file
2497 static const std::array<std::array<std::string, groupSize>, groupNum>
2498 faultLedPinNames = {{
2499 "LED_CPU1_CH1_DIMM1_FAULT",
2500 "LED_CPU1_CH1_DIMM2_FAULT",
2501 "LED_CPU1_CH2_DIMM1_FAULT",
2502 "LED_CPU1_CH2_DIMM2_FAULT",
2503 "LED_CPU1_CH3_DIMM1_FAULT",
2504 "LED_CPU1_CH3_DIMM2_FAULT",
2505 "LED_CPU1_CH4_DIMM1_FAULT",
2506 "LED_CPU1_CH4_DIMM2_FAULT",
2507 "LED_CPU1_CH5_DIMM1_FAULT",
2508 "LED_CPU1_CH5_DIMM2_FAULT",
2509 "LED_CPU1_CH6_DIMM1_FAULT",
2510 "LED_CPU1_CH6_DIMM2_FAULT",
2511 "",
2512 "",
2513 "",
2514 "", // end of group1
2515 "LED_CPU2_CH1_DIMM1_FAULT",
2516 "LED_CPU2_CH1_DIMM2_FAULT",
2517 "LED_CPU2_CH2_DIMM1_FAULT",
2518 "LED_CPU2_CH2_DIMM2_FAULT",
2519 "LED_CPU2_CH3_DIMM1_FAULT",
2520 "LED_CPU2_CH3_DIMM2_FAULT",
2521 "LED_CPU2_CH4_DIMM1_FAULT",
2522 "LED_CPU2_CH4_DIMM2_FAULT",
2523 "LED_CPU2_CH5_DIMM1_FAULT",
2524 "LED_CPU2_CH5_DIMM2_FAULT",
2525 "LED_CPU2_CH6_DIMM1_FAULT",
2526 "LED_CPU2_CH6_DIMM2_FAULT",
2527 "",
2528 "",
2529 "",
2530 "", // endof group2
2531 "LED_CPU3_CH1_DIMM1_FAULT",
2532 "LED_CPU3_CH1_DIMM2_FAULT",
2533 "LED_CPU3_CH2_DIMM1_FAULT",
2534 "LED_CPU3_CH2_DIMM2_FAULT",
2535 "LED_CPU3_CH3_DIMM1_FAULT",
2536 "LED_CPU3_CH3_DIMM2_FAULT",
2537 "LED_CPU3_CH4_DIMM1_FAULT",
2538 "LED_CPU3_CH4_DIMM2_FAULT",
2539 "LED_CPU3_CH5_DIMM1_FAULT",
2540 "LED_CPU3_CH5_DIMM2_FAULT",
2541 "LED_CPU3_CH6_DIMM1_FAULT",
2542 "LED_CPU3_CH6_DIMM2_FAULT",
2543 "",
2544 "",
2545 "",
2546 "", // end of group3
2547 "LED_CPU4_CH1_DIMM1_FAULT",
2548 "LED_CPU4_CH1_DIMM2_FAULT",
2549 "LED_CPU4_CH2_DIMM1_FAULT",
2550 "LED_CPU4_CH2_DIMM2_FAULT",
2551 "LED_CPU4_CH3_DIMM1_FAULT",
2552 "LED_CPU4_CH3_DIMM2_FAULT",
2553 "LED_CPU4_CH4_DIMM1_FAULT",
2554 "LED_CPU4_CH4_DIMM2_FAULT",
2555 "LED_CPU4_CH5_DIMM1_FAULT",
2556 "LED_CPU4_CH5_DIMM2_FAULT",
2557 "LED_CPU4_CH6_DIMM1_FAULT",
2558 "LED_CPU4_CH6_DIMM2_FAULT",
2559 "",
2560 "",
2561 "",
2562 "", // end of group4
2563 "LED_FAN1_FAULT",
2564 "LED_FAN2_FAULT",
2565 "LED_FAN3_FAULT",
2566 "LED_FAN4_FAULT",
2567 "LED_FAN5_FAULT",
2568 "LED_FAN6_FAULT",
2569 "LED_FAN7_FAULT",
2570 "LED_FAN8_FAULT",
2571 "",
2572 "",
2573 "",
2574 "",
2575 "",
2576 "",
2577 "",
2578 "" // end of group5
2579 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002580
Zhikui Rence4e73f2019-12-06 13:59:47 -08002581 // Validate the source, fault type --
2582 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2583 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2584 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2585 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2586 // definition differs based on fault type (Byte 2)
2587 // Type Fan=> Group: 0=FanGroupID, FF-not used
2588 // Byte 5-11 00h, not used
2589 // Byte12 FanLedState [7:0]-Fans 7:0
2590 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2591 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2592 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2593 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2594 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2595 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2596 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2597 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002598 if ((sourceId >= maxFaultSource) ||
2599 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2600 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2601 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2602 {
2603 return ipmi::responseParmOutOfRange();
2604 }
2605
Zhikui Rence4e73f2019-12-06 13:59:47 -08002606 size_t pinGroupOffset = 0;
2607 size_t pinGroupMax = pinSize / groupSize;
2608 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002609 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002610 pinGroupOffset = 4;
2611 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002612 }
2613
2614 switch (RemoteFaultType(faultType))
2615 {
2616 case (RemoteFaultType::fan):
2617 case (RemoteFaultType::memory):
2618 {
2619 if (faultGroup == skipLEDs)
2620 {
2621 return ipmi::responseSuccess();
2622 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002623 // calculate led state bit filed count, each byte has 8bits
2624 // the maximum bits will be 8 * 8 bits
2625 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002626
2627 // assemble ledState
2628 uint64_t ledState = 0;
2629 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002630 for (int i = 0; i < sizeof(ledStateData); i++)
2631 {
2632 ledState = (uint64_t)(ledState << 8);
2633 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2634 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002635 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002636
Zhikui Rence4e73f2019-12-06 13:59:47 -08002637 for (int group = 0; group < pinGroupMax; group++)
2638 {
2639 for (int i = 0; i < groupSize; i++)
2640 { // skip non-existing pins
2641 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2642 {
2643 continue;
2644 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002645
Zhikui Rence4e73f2019-12-06 13:59:47 -08002646 gpiod::line line = gpiod::find_line(
2647 faultLedPinNames[group + pinGroupOffset][i]);
2648 if (!line)
2649 {
2650 phosphor::logging::log<phosphor::logging::level::ERR>(
2651 "Not Find Led Gpio Device!",
2652 phosphor::logging::entry(
2653 "DEVICE=%s",
2654 faultLedPinNames[group + pinGroupOffset][i]
2655 .c_str()));
2656 hasError = true;
2657 continue;
2658 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002659
Zhikui Rence4e73f2019-12-06 13:59:47 -08002660 bool activeHigh =
2661 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2662 try
2663 {
2664 line.request(
2665 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2666 activeHigh
2667 ? 0
2668 : gpiod::line_request::FLAG_ACTIVE_LOW});
2669 line.set_value(ledStateBits[i + group * groupSize]);
2670 }
2671 catch (std::system_error&)
2672 {
2673 phosphor::logging::log<phosphor::logging::level::ERR>(
2674 "Error write Led Gpio Device!",
2675 phosphor::logging::entry(
2676 "DEVICE=%s",
2677 faultLedPinNames[group + pinGroupOffset][i]
2678 .c_str()));
2679 hasError = true;
2680 continue;
2681 }
2682 } // for int i
2683 }
2684 if (hasError)
2685 {
2686 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002687 }
2688 break;
2689 }
2690 default:
2691 {
2692 // now only support two fault types
2693 return ipmi::responseParmOutOfRange();
2694 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002695 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002696 return ipmi::responseSuccess();
2697}
2698
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302699ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2700{
2701 uint8_t prodId = 0;
2702 try
2703 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002704 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302705 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002706 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302707 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2708 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002709 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302710 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2711 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302712 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2713 }
2714 catch (std::exception& e)
2715 {
2716 phosphor::logging::log<phosphor::logging::level::ERR>(
2717 "ipmiOEMReadBoardProductId: Product ID read failed!",
2718 phosphor::logging::entry("ERR=%s", e.what()));
2719 }
2720 return ipmi::responseSuccess(prodId);
2721}
2722
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302723/** @brief implements the get security mode command
2724 * @param ctx - ctx pointer
2725 *
2726 * @returns IPMI completion code with following data
2727 * - restriction mode value - As specified in
2728 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2729 * - special mode value - As specified in
2730 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2731 */
2732ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2733{
2734 namespace securityNameSpace =
2735 sdbusplus::xyz::openbmc_project::Control::Security::server;
2736 uint8_t restrictionModeValue = 0;
2737 uint8_t specialModeValue = 0;
2738
2739 boost::system::error_code ec;
2740 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002741 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302742 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2743 restricionModeProperty);
2744 if (ec)
2745 {
2746 phosphor::logging::log<phosphor::logging::level::ERR>(
2747 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2748 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2749 return ipmi::responseUnspecifiedError();
2750 }
2751 restrictionModeValue = static_cast<uint8_t>(
2752 securityNameSpace::RestrictionMode::convertModesFromString(
2753 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302754 auto varSpecialMode =
2755 ctx->bus->yield_method_call<std::variant<std::string>>(
2756 ctx->yield, ec, specialModeService, specialModeBasePath,
2757 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2758 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302759 if (ec)
2760 {
2761 phosphor::logging::log<phosphor::logging::level::ERR>(
2762 "ipmiGetSecurityMode: failed to get SpecialMode property",
2763 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2764 // fall through, let us not worry about SpecialMode property, which is
2765 // not required in user scenario
2766 }
2767 else
2768 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302769 specialModeValue = static_cast<uint8_t>(
2770 securityNameSpace::SpecialMode::convertModesFromString(
2771 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302772 }
2773 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2774}
2775
2776/** @brief implements the set security mode command
2777 * Command allows to upgrade the restriction mode and won't allow
2778 * to downgrade from system interface
2779 * @param ctx - ctx pointer
2780 * @param restrictionMode - restriction mode value to be set.
2781 *
2782 * @returns IPMI completion code
2783 */
2784ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302785 uint8_t restrictionMode,
2786 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302787{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302788#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2789 if (specialMode)
2790 {
2791 return ipmi::responseReqDataLenInvalid();
2792 }
2793#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302794 namespace securityNameSpace =
2795 sdbusplus::xyz::openbmc_project::Control::Security::server;
2796
2797 ChannelInfo chInfo;
2798 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2799 {
2800 phosphor::logging::log<phosphor::logging::level::ERR>(
2801 "ipmiSetSecurityMode: Failed to get Channel Info",
2802 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2803 return ipmi::responseUnspecifiedError();
2804 }
2805 auto reqMode =
2806 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2807
2808 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2809 (reqMode >
2810 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2811 {
2812 return ipmi::responseInvalidFieldRequest();
2813 }
2814
2815 boost::system::error_code ec;
2816 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002817 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302818 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2819 restricionModeProperty);
2820 if (ec)
2821 {
2822 phosphor::logging::log<phosphor::logging::level::ERR>(
2823 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2824 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2825 return ipmi::responseUnspecifiedError();
2826 }
2827 auto currentRestrictionMode =
2828 securityNameSpace::RestrictionMode::convertModesFromString(
2829 std::get<std::string>(varRestrMode));
2830
2831 if (chInfo.mediumType !=
2832 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2833 currentRestrictionMode > reqMode)
2834 {
2835 phosphor::logging::log<phosphor::logging::level::ERR>(
2836 "ipmiSetSecurityMode - Downgrading security mode not supported "
2837 "through system interface",
2838 phosphor::logging::entry(
2839 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2840 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2841 return ipmi::responseCommandNotAvailable();
2842 }
2843
2844 ec.clear();
2845 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002846 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302847 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2848 restricionModeProperty,
2849 static_cast<std::variant<std::string>>(
2850 securityNameSpace::convertForMessage(reqMode)));
2851
2852 if (ec)
2853 {
2854 phosphor::logging::log<phosphor::logging::level::ERR>(
2855 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2856 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2857 return ipmi::responseUnspecifiedError();
2858 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302859
2860#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2861 if (specialMode)
2862 {
Jayaprakash Mutyalad77489f2020-09-05 01:00:04 +00002863 constexpr uint8_t mfgMode = 0x01;
2864 // Manufacturing mode is reserved. So can't enable this mode.
2865 if (specialMode.value() == mfgMode)
2866 {
2867 phosphor::logging::log<phosphor::logging::level::INFO>(
2868 "ipmiSetSecurityMode: Can't enable Manufacturing mode");
2869 return ipmi::responseInvalidFieldRequest();
2870 }
2871
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302872 ec.clear();
2873 ctx->bus->yield_method_call<>(
2874 ctx->yield, ec, specialModeService, specialModeBasePath,
2875 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2876 specialModeProperty,
2877 static_cast<std::variant<std::string>>(
2878 securityNameSpace::convertForMessage(
2879 static_cast<securityNameSpace::SpecialMode::Modes>(
2880 specialMode.value()))));
2881
2882 if (ec)
2883 {
2884 phosphor::logging::log<phosphor::logging::level::ERR>(
2885 "ipmiSetSecurityMode: failed to set SpecialMode property",
2886 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2887 return ipmi::responseUnspecifiedError();
2888 }
2889 }
2890#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302891 return ipmi::responseSuccess();
2892}
2893
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002894ipmi::RspType<uint8_t /* restore status */>
2895 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2896{
2897 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2898
2899 if (clr != expClr)
2900 {
2901 return ipmi::responseInvalidFieldRequest();
2902 }
2903 constexpr uint8_t cmdStatus = 0;
2904 constexpr uint8_t cmdDefaultRestore = 0xaa;
2905 constexpr uint8_t cmdFullRestore = 0xbb;
2906 constexpr uint8_t cmdFormat = 0xcc;
2907
2908 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2909
2910 switch (cmd)
2911 {
2912 case cmdStatus:
2913 break;
2914 case cmdDefaultRestore:
2915 case cmdFullRestore:
2916 case cmdFormat:
2917 {
2918 // write file to rwfs root
2919 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2920 std::ofstream restoreFile(restoreOpFname);
2921 if (!restoreFile)
2922 {
2923 return ipmi::responseUnspecifiedError();
2924 }
2925 restoreFile << value << "\n";
Arun P. Mohananba1fbc82021-04-26 11:26:53 +05302926
2927 phosphor::logging::log<phosphor::logging::level::WARNING>(
2928 "Restore to default will be performed on next BMC boot",
2929 phosphor::logging::entry("ACTION=0x%0X", cmd));
2930
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002931 break;
2932 }
2933 default:
2934 return ipmi::responseInvalidFieldRequest();
2935 }
2936
2937 constexpr uint8_t restorePending = 0;
2938 constexpr uint8_t restoreComplete = 1;
2939
2940 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2941 ? restorePending
2942 : restoreComplete;
2943 return ipmi::responseSuccess(restoreStatus);
2944}
2945
Chen Yugang39736d52019-07-12 16:24:33 +08002946ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2947{
2948 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002949 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002950
2951 try
2952 {
2953 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2954 std::string service =
2955 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2956 Value variant =
2957 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2958 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2959
2960 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2961 std::get<std::string>(variant)))
2962 {
2963 case nmi::NMISource::BMCSourceSignal::None:
2964 bmcSource = static_cast<uint8_t>(NmiSource::none);
2965 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002966 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2967 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002968 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002969 case nmi::NMISource::BMCSourceSignal::Watchdog:
2970 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002971 break;
2972 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2973 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2974 break;
2975 case nmi::NMISource::BMCSourceSignal::MemoryError:
2976 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2977 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002978 case nmi::NMISource::BMCSourceSignal::PciBusError:
2979 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002980 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002981 case nmi::NMISource::BMCSourceSignal::PCH:
2982 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002983 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002984 case nmi::NMISource::BMCSourceSignal::Chipset:
2985 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002986 break;
2987 default:
2988 phosphor::logging::log<phosphor::logging::level::ERR>(
2989 "NMI source: invalid property!",
2990 phosphor::logging::entry(
2991 "PROP=%s", std::get<std::string>(variant).c_str()));
2992 return ipmi::responseResponseError();
2993 }
2994 }
2995 catch (sdbusplus::exception::SdBusError& e)
2996 {
2997 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2998 return ipmi::responseResponseError();
2999 }
3000
3001 return ipmi::responseSuccess(bmcSource);
3002}
3003
3004ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
3005{
Chen Yugang97cf96e2019-11-01 08:55:11 +08003006 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08003007
3008 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
3009 nmi::NMISource::BMCSourceSignal::None;
3010
3011 switch (NmiSource(sourceId))
3012 {
3013 case NmiSource::none:
3014 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
3015 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003016 case NmiSource::frontPanelButton:
3017 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003018 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003019 case NmiSource::watchdog:
3020 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003021 break;
3022 case NmiSource::chassisCmd:
3023 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3024 break;
3025 case NmiSource::memoryError:
3026 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3027 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003028 case NmiSource::pciBusError:
3029 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003030 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003031 case NmiSource::pch:
3032 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003033 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003034 case NmiSource::chipset:
3035 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003036 break;
3037 default:
3038 phosphor::logging::log<phosphor::logging::level::ERR>(
3039 "NMI source: invalid property!");
3040 return ipmi::responseResponseError();
3041 }
3042
3043 try
3044 {
3045 // keep NMI signal source
3046 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3047 std::string service =
3048 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003049 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3050 oemNmiBmcSourceObjPathProp,
3051 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003052 // set Enabled property to inform NMI source handling
3053 // to trigger a NMI_OUT BSOD.
3054 // if it's triggered by NMI source property changed,
3055 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3056 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3057 {
3058 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3059 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3060 static_cast<bool>(true));
3061 }
Chen Yugang39736d52019-07-12 16:24:33 +08003062 }
3063 catch (sdbusplus::exception_t& e)
3064 {
3065 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3066 return ipmi::responseResponseError();
3067 }
3068
3069 return ipmi::responseSuccess();
3070}
3071
James Feist63efafa2019-07-24 12:39:21 -07003072namespace dimmOffset
3073{
3074constexpr const char* dimmPower = "DimmPower";
3075constexpr const char* staticCltt = "StaticCltt";
3076constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3077constexpr const char* offsetInterface =
3078 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3079constexpr const char* property = "DimmOffset";
3080
3081}; // namespace dimmOffset
3082
3083ipmi::RspType<>
3084 ipmiOEMSetDimmOffset(uint8_t type,
3085 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3086{
3087 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3088 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3089 {
3090 return ipmi::responseInvalidFieldRequest();
3091 }
3092
3093 if (data.empty())
3094 {
3095 return ipmi::responseInvalidFieldRequest();
3096 }
3097 nlohmann::json json;
3098
3099 std::ifstream jsonStream(dimmOffsetFile);
3100 if (jsonStream.good())
3101 {
3102 json = nlohmann::json::parse(jsonStream, nullptr, false);
3103 if (json.is_discarded())
3104 {
3105 json = nlohmann::json();
3106 }
3107 jsonStream.close();
3108 }
3109
3110 std::string typeName;
3111 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3112 {
3113 typeName = dimmOffset::dimmPower;
3114 }
3115 else
3116 {
3117 typeName = dimmOffset::staticCltt;
3118 }
3119
3120 nlohmann::json& field = json[typeName];
3121
3122 for (const auto& [index, value] : data)
3123 {
3124 field[index] = value;
3125 }
3126
3127 for (nlohmann::json& val : field)
3128 {
3129 if (val == nullptr)
3130 {
3131 val = static_cast<uint8_t>(0);
3132 }
3133 }
3134
3135 std::ofstream output(dimmOffsetFile);
3136 if (!output.good())
3137 {
3138 std::cerr << "Error writing json file\n";
3139 return ipmi::responseResponseError();
3140 }
3141
3142 output << json.dump(4);
3143
3144 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3145 {
3146 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3147
3148 std::variant<std::vector<uint8_t>> offsets =
3149 field.get<std::vector<uint8_t>>();
3150 auto call = bus->new_method_call(
3151 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3152 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3153 try
3154 {
3155 bus->call(call);
3156 }
3157 catch (sdbusplus::exception_t& e)
3158 {
3159 phosphor::logging::log<phosphor::logging::level::ERR>(
3160 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3161 phosphor::logging::entry("ERR=%s", e.what()));
3162 return ipmi::responseResponseError();
3163 }
3164 }
3165
3166 return ipmi::responseSuccess();
3167}
3168
3169ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3170{
3171
3172 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3173 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3174 {
3175 return ipmi::responseInvalidFieldRequest();
3176 }
3177
3178 std::ifstream jsonStream(dimmOffsetFile);
3179
3180 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3181 if (json.is_discarded())
3182 {
3183 std::cerr << "File error in " << dimmOffsetFile << "\n";
3184 return ipmi::responseResponseError();
3185 }
3186
3187 std::string typeName;
3188 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3189 {
3190 typeName = dimmOffset::dimmPower;
3191 }
3192 else
3193 {
3194 typeName = dimmOffset::staticCltt;
3195 }
3196
3197 auto it = json.find(typeName);
3198 if (it == json.end())
3199 {
3200 return ipmi::responseInvalidFieldRequest();
3201 }
3202
3203 if (it->size() <= index)
3204 {
3205 return ipmi::responseInvalidFieldRequest();
3206 }
3207
3208 uint8_t resp = it->at(index).get<uint8_t>();
3209 return ipmi::responseSuccess(resp);
3210}
3211
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003212namespace boot_options
3213{
3214
3215using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3216using IpmiValue = uint8_t;
3217constexpr auto ipmiDefault = 0;
3218
3219std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3220 {0x01, Source::Sources::Network},
3221 {0x02, Source::Sources::Disk},
3222 {0x05, Source::Sources::ExternalMedia},
3223 {0x0f, Source::Sources::RemovableMedia},
3224 {ipmiDefault, Source::Sources::Default}};
3225
3226std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003227 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003228
3229std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3230 {Source::Sources::Network, 0x01},
3231 {Source::Sources::Disk, 0x02},
3232 {Source::Sources::ExternalMedia, 0x05},
3233 {Source::Sources::RemovableMedia, 0x0f},
3234 {Source::Sources::Default, ipmiDefault}};
3235
3236std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003237 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003238
3239static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3240static constexpr auto bootSourceIntf =
3241 "xyz.openbmc_project.Control.Boot.Source";
3242static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3243static constexpr auto persistentObjPath =
3244 "/xyz/openbmc_project/control/host0/boot";
3245static constexpr auto oneTimePath =
3246 "/xyz/openbmc_project/control/host0/boot/one_time";
3247static constexpr auto bootSourceProp = "BootSource";
3248static constexpr auto bootModeProp = "BootMode";
3249static constexpr auto oneTimeBootEnableProp = "Enabled";
3250static constexpr auto httpBootMode =
3251 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3252
3253enum class BootOptionParameter : size_t
3254{
3255 setInProgress = 0x0,
3256 bootFlags = 0x5,
3257};
3258static constexpr uint8_t setComplete = 0x0;
3259static constexpr uint8_t setInProgress = 0x1;
3260static uint8_t transferStatus = setComplete;
3261static constexpr uint8_t setParmVersion = 0x01;
3262static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3263static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3264static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3265static constexpr uint8_t httpBoot = 0xd;
3266static constexpr uint8_t bootSourceMask = 0x3c;
3267
3268} // namespace boot_options
3269
3270ipmi::RspType<uint8_t, // version
3271 uint8_t, // param
3272 uint8_t, // data0, dependent on parameter
3273 std::optional<uint8_t> // data1, dependent on parameter
3274 >
3275 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3276{
3277 using namespace boot_options;
3278 uint8_t bootOption = 0;
3279
3280 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3281 {
3282 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3283 std::nullopt);
3284 }
3285
3286 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3287 {
3288 phosphor::logging::log<phosphor::logging::level::ERR>(
3289 "Unsupported parameter");
3290 return ipmi::responseResponseError();
3291 }
3292
3293 try
3294 {
3295 auto oneTimeEnabled = false;
3296 // read one time Enabled property
3297 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3298 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3299 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3300 enabledIntf, oneTimeBootEnableProp);
3301 oneTimeEnabled = std::get<bool>(variant);
3302
3303 // get BootSource and BootMode properties
3304 // according to oneTimeEnable
3305 auto bootObjPath = oneTimePath;
3306 if (oneTimeEnabled == false)
3307 {
3308 bootObjPath = persistentObjPath;
3309 }
3310
3311 service = getService(*dbus, bootModeIntf, bootObjPath);
3312 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3313 bootModeProp);
3314
3315 auto bootMode =
3316 Mode::convertModesFromString(std::get<std::string>(variant));
3317
3318 service = getService(*dbus, bootSourceIntf, bootObjPath);
3319 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3320 bootSourceProp);
3321
3322 if (std::get<std::string>(variant) == httpBootMode)
3323 {
3324 bootOption = httpBoot;
3325 }
3326 else
3327 {
3328 auto bootSource = Source::convertSourcesFromString(
3329 std::get<std::string>(variant));
3330 bootOption = sourceDbusToIpmi.at(bootSource);
3331 if (Source::Sources::Default == bootSource)
3332 {
3333 bootOption = modeDbusToIpmi.at(bootMode);
3334 }
3335 }
3336
3337 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3338 : setParmBootFlagsValidPermanent;
3339 bootOption <<= 2; // shift for responseconstexpr
3340 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3341 bootOption);
3342 }
3343 catch (sdbusplus::exception_t& e)
3344 {
3345 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3346 return ipmi::responseResponseError();
3347 }
3348}
3349
3350ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3351 std::optional<uint8_t> bootOption)
3352{
3353 using namespace boot_options;
3354 auto oneTimeEnabled = false;
3355
3356 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3357 {
3358 if (bootOption)
3359 {
3360 return ipmi::responseReqDataLenInvalid();
3361 }
3362
3363 if (transferStatus == setInProgress)
3364 {
3365 phosphor::logging::log<phosphor::logging::level::ERR>(
3366 "boot option set in progress!");
3367 return ipmi::responseResponseError();
3368 }
3369
3370 transferStatus = bootParam;
3371 return ipmi::responseSuccess();
3372 }
3373
3374 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3375 {
3376 phosphor::logging::log<phosphor::logging::level::ERR>(
3377 "Unsupported parameter");
3378 return ipmi::responseResponseError();
3379 }
3380
3381 if (!bootOption)
3382 {
3383 return ipmi::responseReqDataLenInvalid();
3384 }
3385
3386 if (((bootOption.value() & bootSourceMask) >> 2) !=
3387 httpBoot) // not http boot, exit
3388 {
3389 phosphor::logging::log<phosphor::logging::level::ERR>(
3390 "wrong boot option parameter!");
3391 return ipmi::responseParmOutOfRange();
3392 }
3393
3394 try
3395 {
3396 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3397 setParmBootFlagsPermanent;
3398
3399 // read one time Enabled property
3400 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3401 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3402 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3403 enabledIntf, oneTimeBootEnableProp);
3404 oneTimeEnabled = std::get<bool>(variant);
3405
3406 /*
3407 * Check if the current boot setting is onetime or permanent, if the
3408 * request in the command is otherwise, then set the "Enabled"
3409 * property in one_time object path to 'True' to indicate onetime
3410 * and 'False' to indicate permanent.
3411 *
3412 * Once the onetime/permanent setting is applied, then the bootMode
3413 * and bootSource is updated for the corresponding object.
3414 */
3415 if (permanent == oneTimeEnabled)
3416 {
3417 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3418 oneTimeBootEnableProp, !permanent);
3419 }
3420
3421 // set BootSource and BootMode properties
3422 // according to oneTimeEnable or persistent
3423 auto bootObjPath = oneTimePath;
3424 if (oneTimeEnabled == false)
3425 {
3426 bootObjPath = persistentObjPath;
3427 }
3428 std::string bootMode =
3429 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3430 std::string bootSource = httpBootMode;
3431
3432 service = getService(*dbus, bootModeIntf, bootObjPath);
3433 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3434 bootMode);
3435
3436 service = getService(*dbus, bootSourceIntf, bootObjPath);
3437 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3438 bootSourceProp, bootSource);
3439 }
3440 catch (sdbusplus::exception_t& e)
3441 {
3442 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3443 return ipmi::responseResponseError();
3444 }
3445
3446 return ipmi::responseSuccess();
3447}
3448
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003449using BasicVariantType =
3450 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3451 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3452 uint16_t, uint8_t, bool>;
3453using PropertyMapType =
3454 boost::container::flat_map<std::string, BasicVariantType>;
3455static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3456 "xyz.openbmc_project.Configuration.PSUPresence"};
3457int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3458 std::vector<uint64_t>& addrTable)
3459{
3460 boost::system::error_code ec;
3461 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3462 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3463 "/xyz/openbmc_project/object_mapper",
3464 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3465 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3466 if (ec)
3467 {
3468 phosphor::logging::log<phosphor::logging::level::ERR>(
3469 "Failed to set dbus property to cold redundancy");
3470 return -1;
3471 }
3472 for (const auto& object : subtree)
3473 {
3474 std::string pathName = object.first;
3475 for (const auto& serviceIface : object.second)
3476 {
3477 std::string serviceName = serviceIface.first;
3478
3479 ec.clear();
3480 PropertyMapType propMap =
3481 ctx->bus->yield_method_call<PropertyMapType>(
3482 ctx->yield, ec, serviceName, pathName,
3483 "org.freedesktop.DBus.Properties", "GetAll",
3484 "xyz.openbmc_project.Configuration.PSUPresence");
3485 if (ec)
3486 {
3487 phosphor::logging::log<phosphor::logging::level::ERR>(
3488 "Failed to set dbus property to cold redundancy");
3489 return -1;
3490 }
3491 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3492 auto psuAddress =
3493 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3494
3495 if (psuBus == nullptr || psuAddress == nullptr)
3496 {
3497 std::cerr << "error finding necessary "
3498 "entry in configuration\n";
3499 return -1;
3500 }
3501 bus = static_cast<uint8_t>(*psuBus);
3502 addrTable = *psuAddress;
3503 return 0;
3504 }
3505 }
3506 return -1;
3507}
3508
3509static const constexpr uint8_t addrOffset = 8;
3510static const constexpr uint8_t psuRevision = 0xd9;
3511static const constexpr uint8_t defaultPSUBus = 7;
3512// Second Minor, Primary Minor, Major
3513static const constexpr size_t verLen = 3;
3514ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3515{
3516 uint8_t bus = defaultPSUBus;
3517 std::vector<uint64_t> addrTable;
3518 std::vector<uint8_t> result;
3519 if (getPSUAddress(ctx, bus, addrTable))
3520 {
3521 std::cerr << "Failed to get PSU bus and address\n";
3522 return ipmi::responseResponseError();
3523 }
3524
3525 for (const auto& slaveAddr : addrTable)
3526 {
3527 std::vector<uint8_t> writeData = {psuRevision};
3528 std::vector<uint8_t> readBuf(verLen);
3529 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3530 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3531
3532 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3533 if (retI2C != ipmi::ccSuccess)
3534 {
3535 for (size_t idx = 0; idx < verLen; idx++)
3536 {
3537 result.emplace_back(0x00);
3538 }
3539 }
3540 else
3541 {
3542 for (const uint8_t& data : readBuf)
3543 {
3544 result.emplace_back(data);
3545 }
3546 }
3547 }
3548
3549 return ipmi::responseSuccess(result);
3550}
3551
srikanta mondal2030d7c2020-05-03 17:25:25 +00003552std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx,
3553 const std::string& name)
3554{
3555 Value dbusValue = 0;
3556 std::string serviceName;
3557
3558 boost::system::error_code ec =
3559 ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName);
3560
3561 if (ec)
3562 {
3563 phosphor::logging::log<phosphor::logging::level::ERR>(
3564 "Failed to perform Multinode getService.");
3565 return std::nullopt;
3566 }
3567
3568 ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath,
3569 multiNodeIntf, name, dbusValue);
3570 if (ec)
3571 {
3572 phosphor::logging::log<phosphor::logging::level::ERR>(
3573 "Failed to perform Multinode get property");
3574 return std::nullopt;
3575 }
3576
3577 auto multiNodeVal = std::get_if<uint8_t>(&dbusValue);
3578 if (!multiNodeVal)
3579 {
3580 phosphor::logging::log<phosphor::logging::level::ERR>(
3581 "getMultiNodeInfoPresence: error to get multinode");
3582 return std::nullopt;
3583 }
3584 return *multiNodeVal;
3585}
3586
3587/** @brief implements OEM get reading command
3588 * @param domain ID
3589 * @param reading Type
3590 * - 00h = platform Power Consumption
3591 * - 01h = inlet Air Temp
3592 * - 02h = icc_TDC from PECI
3593 * @param reserved, write as 0000h
3594 *
3595 * @returns IPMI completion code plus response data
3596 * - response
3597 * - domain ID
3598 * - reading Type
3599 * - 00h = platform Power Consumption
3600 * - 01h = inlet Air Temp
3601 * - 02h = icc_TDC from PECI
3602 * - reading
3603 */
3604ipmi::RspType<uint4_t, // domain ID
3605 uint4_t, // reading Type
3606 uint16_t // reading Value
3607 >
3608 ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId,
3609 uint4_t readingType, uint16_t reserved)
3610{
3611 constexpr uint8_t platformPower = 0;
3612 constexpr uint8_t inletAirTemp = 1;
3613 constexpr uint8_t iccTdc = 2;
3614
3615 if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved)
3616 {
3617 return ipmi::responseInvalidFieldRequest();
3618 }
3619
3620 // This command should run only from multi-node product.
3621 // For all other platforms this command will return invalid.
3622
3623 std::optional<uint8_t> nodeInfo =
3624 getMultiNodeInfoPresence(ctx, "NodePresence");
3625 if (!nodeInfo || !*nodeInfo)
3626 {
3627 return ipmi::responseInvalidCommand();
3628 }
3629
3630 uint16_t oemReadingValue = 0;
3631 if (static_cast<uint8_t>(readingType) == inletAirTemp)
3632 {
3633 double value = 0;
3634 boost::system::error_code ec = ipmi::getDbusProperty(
3635 ctx, "xyz.openbmc_project.HwmonTempSensor",
3636 "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp",
3637 "xyz.openbmc_project.Sensor.Value", "Value", value);
3638 if (ec)
3639 {
3640 phosphor::logging::log<phosphor::logging::level::ERR>(
3641 "Failed to get BMC Get OEM temperature",
3642 phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str()));
3643 return ipmi::responseUnspecifiedError();
3644 }
3645 // Take the Inlet temperature
3646 oemReadingValue = static_cast<uint16_t>(value);
3647 }
3648 else
3649 {
3650 phosphor::logging::log<phosphor::logging::level::ERR>(
3651 "Currently Get OEM Reading support only for Inlet Air Temp");
3652 return ipmi::responseParmOutOfRange();
3653 }
3654 return ipmi::responseSuccess(domainId, readingType, oemReadingValue);
3655}
3656
AppaRao Puli28972062019-11-11 02:04:45 +05303657/** @brief implements the maximum size of
3658 * bridgeable messages used between KCS and
3659 * IPMB interfacesget security mode command.
3660 *
3661 * @returns IPMI completion code with following data
3662 * - KCS Buffer Size (In multiples of four bytes)
3663 * - IPMB Buffer Size (In multiples of four bytes)
3664 **/
3665ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3666{
3667 // for now this is hard coded; really this number is dependent on
3668 // the BMC kcs driver as well as the host kcs driver....
3669 // we can't know the latter.
3670 uint8_t kcsMaxBufferSize = 63 / 4;
3671 uint8_t ipmbMaxBufferSize = 128 / 4;
3672
3673 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3674}
3675
Jason M. Bills64796042018-10-03 16:51:55 -07003676static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003677{
3678 phosphor::logging::log<phosphor::logging::level::INFO>(
3679 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003680 ipmiPrintAndRegister(intel::netFnGeneral,
3681 intel::general::cmdGetChassisIdentifier, NULL,
3682 ipmiOEMGetChassisIdentifier,
3683 PRIVILEGE_USER); // get chassis identifier
3684
3685 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3686 NULL, ipmiOEMSetSystemGUID,
3687 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003688
3689 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003690 registerHandler(prioOemBase, intel::netFnGeneral,
3691 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3692 ipmiOEMDisableBMCSystemReset);
3693
Jason M. Billsb02bf092019-08-15 13:01:56 -07003694 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003695 registerHandler(prioOemBase, intel::netFnGeneral,
3696 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3697 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003698
Vernon Mauery98bbf692019-09-16 11:14:59 -07003699 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3700 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003701
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003702 registerHandler(prioOemBase, intel::netFnGeneral,
3703 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3704 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003705
Vernon Mauery98bbf692019-09-16 11:14:59 -07003706 ipmiPrintAndRegister(intel::netFnGeneral,
3707 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3708 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303709
Vernon Mauery98bbf692019-09-16 11:14:59 -07003710 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3711 intel::general::cmdSendEmbeddedFWUpdStatus,
3712 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303713
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303714 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3715 Privilege::Admin, ipmiOEMSlotIpmb);
3716
Vernon Mauery98bbf692019-09-16 11:14:59 -07003717 ipmiPrintAndRegister(intel::netFnGeneral,
3718 intel::general::cmdSetPowerRestoreDelay, NULL,
3719 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3720
3721 ipmiPrintAndRegister(intel::netFnGeneral,
3722 intel::general::cmdGetPowerRestoreDelay, NULL,
3723 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3724
3725 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3726 intel::general::cmdSetOEMUser2Activation,
3727 Privilege::Callback, ipmiOEMSetUser2Activation);
3728
3729 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3730 intel::general::cmdSetSpecialUserPassword,
3731 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303732
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003733 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003734 registerHandler(prioOemBase, intel::netFnGeneral,
3735 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3736 ipmiOEMGetProcessorErrConfig);
3737
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003738 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003739 registerHandler(prioOemBase, intel::netFnGeneral,
3740 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3741 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003742
Vernon Mauery98bbf692019-09-16 11:14:59 -07003743 ipmiPrintAndRegister(intel::netFnGeneral,
3744 intel::general::cmdSetShutdownPolicy, NULL,
3745 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003746
Vernon Mauery98bbf692019-09-16 11:14:59 -07003747 ipmiPrintAndRegister(intel::netFnGeneral,
3748 intel::general::cmdGetShutdownPolicy, NULL,
3749 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003750
anil kumar appanaf945eee2019-09-25 23:29:11 +00003751 registerHandler(prioOemBase, intel::netFnGeneral,
3752 intel::general::cmdSetFanConfig, Privilege::User,
3753 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003754
Vernon Mauery98bbf692019-09-16 11:14:59 -07003755 registerHandler(prioOemBase, intel::netFnGeneral,
3756 intel::general::cmdGetFanConfig, Privilege::User,
3757 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003758
Vernon Mauery98bbf692019-09-16 11:14:59 -07003759 registerHandler(prioOemBase, intel::netFnGeneral,
3760 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3761 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003762
Vernon Mauery98bbf692019-09-16 11:14:59 -07003763 registerHandler(prioOemBase, intel::netFnGeneral,
3764 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3765 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003766
Vernon Mauery98bbf692019-09-16 11:14:59 -07003767 registerHandler(prioOemBase, intel::netFnGeneral,
3768 intel::general::cmdSetFscParameter, Privilege::User,
3769 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003770
Vernon Mauery98bbf692019-09-16 11:14:59 -07003771 registerHandler(prioOemBase, intel::netFnGeneral,
3772 intel::general::cmdGetFscParameter, Privilege::User,
3773 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303774
Vernon Mauery98bbf692019-09-16 11:14:59 -07003775 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3776 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3777 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003778
Vernon Mauery98bbf692019-09-16 11:14:59 -07003779 registerHandler(prioOemBase, intel::netFnGeneral,
3780 intel::general::cmdGetNmiStatus, Privilege::User,
3781 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003782
Vernon Mauery98bbf692019-09-16 11:14:59 -07003783 registerHandler(prioOemBase, intel::netFnGeneral,
3784 intel::general::cmdSetNmiStatus, Privilege::Operator,
3785 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003786
Vernon Mauery98bbf692019-09-16 11:14:59 -07003787 registerHandler(prioOemBase, intel::netFnGeneral,
3788 intel::general::cmdGetEfiBootOptions, Privilege::User,
3789 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003790
Vernon Mauery98bbf692019-09-16 11:14:59 -07003791 registerHandler(prioOemBase, intel::netFnGeneral,
3792 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3793 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303794
Vernon Mauery98bbf692019-09-16 11:14:59 -07003795 registerHandler(prioOemBase, intel::netFnGeneral,
3796 intel::general::cmdGetSecurityMode, Privilege::User,
3797 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303798
Vernon Mauery98bbf692019-09-16 11:14:59 -07003799 registerHandler(prioOemBase, intel::netFnGeneral,
3800 intel::general::cmdSetSecurityMode, Privilege::Admin,
3801 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003802
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003803 registerHandler(prioOemBase, intel::netFnGeneral,
3804 intel::general::cmdGetLEDStatus, Privilege::Admin,
3805 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003806
Vernon Mauery98bbf692019-09-16 11:14:59 -07003807 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3808 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3809 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3810
3811 registerHandler(prioOemBase, intel::netFnGeneral,
3812 intel::general::cmdSetFaultIndication, Privilege::Operator,
3813 ipmiOEMSetFaultIndication);
3814
3815 registerHandler(prioOemBase, intel::netFnGeneral,
3816 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3817 ipmiOEMSetCRConfig);
3818
3819 registerHandler(prioOemBase, intel::netFnGeneral,
3820 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3821 ipmiOEMGetCRConfig);
3822
3823 registerHandler(prioOemBase, intel::netFnGeneral,
3824 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003825 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003826
Vernon Mauery98bbf692019-09-16 11:14:59 -07003827 registerHandler(prioOemBase, intel::netFnGeneral,
3828 intel::general::cmdSetDimmOffset, Privilege::Operator,
3829 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003830
Vernon Mauery98bbf692019-09-16 11:14:59 -07003831 registerHandler(prioOemBase, intel::netFnGeneral,
3832 intel::general::cmdGetDimmOffset, Privilege::Operator,
3833 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003834
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003835 registerHandler(prioOemBase, intel::netFnGeneral,
3836 intel::general::cmdGetPSUVersion, Privilege::User,
3837 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303838
3839 registerHandler(prioOemBase, intel::netFnGeneral,
3840 intel::general::cmdGetBufferSize, Privilege::User,
3841 ipmiOEMGetBufferSize);
srikanta mondal2030d7c2020-05-03 17:25:25 +00003842
3843 registerHandler(prioOemBase, intel::netFnGeneral,
3844 intel::general::cmdOEMGetReading, Privilege::User,
3845 ipmiOEMGetReading);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003846}
3847
3848} // namespace ipmi