blob: 580bfd5bdf9dc8ae370afeb873b782a153686f35 [file] [log] [blame]
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001/*
2// Copyright (c) 2018 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16
Jason M. Bills64796042018-10-03 16:51:55 -070017#include "xyz/openbmc_project/Common/error.hpp"
Kuiying Wang45f04982018-12-26 09:23:08 +080018#include "xyz/openbmc_project/Led/Physical/server.hpp"
Jason M. Bills64796042018-10-03 16:51:55 -070019
Jia, Chunhuicc49b542019-03-20 15:41:07 +080020#include <systemd/sd-journal.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080021
Chen Yugang7a04f3a2019-10-08 11:12:35 +080022#include <appcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080023#include <array>
James Feist91244a62019-02-19 15:04:54 -080024#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080025#include <boost/process/child.hpp>
26#include <boost/process/io.hpp>
Yong Li0669d192019-05-06 14:01:46 +080027#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070028#include <commandutils.hpp>
Vernon Mauery4ac799d2019-05-20 15:50:37 -070029#include <filesystem>
Zhikui Rence4e73f2019-12-06 13:59:47 -080030#include <gpiod.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080031#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080032#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070033#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070034#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080036#include <phosphor-logging/log.hpp>
Chen Yugang7a04f3a2019-10-08 11:12:35 +080037#include <regex>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080038#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053039#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080040#include <string>
James Feist91244a62019-02-19 15:04:54 -080041#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080042#include <vector>
Chen Yugang97cf96e2019-11-01 08:55:11 +080043#include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp>
Chen,Yugang4f7e76b2019-08-20 09:28:06 +080044#include <xyz/openbmc_project/Control/Boot/Mode/server.hpp>
45#include <xyz/openbmc_project/Control/Boot/Source/server.hpp>
Cheng C Yang773703a2019-08-15 09:41:11 +080046#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053047#include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp>
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +053048#include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080049
50namespace ipmi
51{
Jason M. Bills64796042018-10-03 16:51:55 -070052static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070053
Jason M. Bills64796042018-10-03 16:51:55 -070054static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080055
Suryakanth Sekard509eb92018-11-15 17:44:11 +053056static constexpr auto ethernetIntf =
57 "xyz.openbmc_project.Network.EthernetInterface";
58static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
59static constexpr auto networkService = "xyz.openbmc_project.Network";
60static constexpr auto networkRoot = "/xyz/openbmc_project/network";
61
Chen Yugang97cf96e2019-11-01 08:55:11 +080062static constexpr const char* oemNmiSourceIntf =
63 "xyz.openbmc_project.Chassis.Control.NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080064static constexpr const char* oemNmiSourceObjPath =
Chen Yugang97cf96e2019-11-01 08:55:11 +080065 "/xyz/openbmc_project/Chassis/Control/NMISource";
Chen Yugang39736d52019-07-12 16:24:33 +080066static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
67static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
68
James Feist63efafa2019-07-24 12:39:21 -070069static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
70
Chen Yugang39736d52019-07-12 16:24:33 +080071enum class NmiSource : uint8_t
72{
73 none = 0,
Chen Yugang97cf96e2019-11-01 08:55:11 +080074 frontPanelButton = 1,
75 watchdog = 2,
76 chassisCmd = 3,
77 memoryError = 4,
78 pciBusError = 5,
79 pch = 6,
80 chipset = 7,
Chen Yugang39736d52019-07-12 16:24:33 +080081};
82
Suryakanth Sekar822b0b42019-11-15 18:32:53 +053083enum class SpecialUserIndex : uint8_t
84{
85 rootUser = 0,
86 atScaleDebugUser = 1
87};
88
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +053089static constexpr const char* restricionModeService =
90 "xyz.openbmc_project.RestrictionMode.Manager";
91static constexpr const char* restricionModeBasePath =
92 "/xyz/openbmc_project/control/security/restriction_mode";
93static constexpr const char* restricionModeIntf =
94 "xyz.openbmc_project.Control.Security.RestrictionMode";
95static constexpr const char* restricionModeProperty = "RestrictionMode";
96
97static constexpr const char* specialModeService =
98 "xyz.openbmc_project.SpecialMode";
99static constexpr const char* specialModeBasePath =
Richard Marian Thomaiyara7b74282019-09-22 21:53:14 +0530100 "/xyz/openbmc_project/security/special_mode";
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +0530101static constexpr const char* specialModeIntf =
102 "xyz.openbmc_project.Security.SpecialMode";
103static constexpr const char* specialModeProperty = "SpecialMode";
104
105static constexpr const char* dBusPropertyIntf =
106 "org.freedesktop.DBus.Properties";
107static constexpr const char* dBusPropertyGetMethod = "Get";
108static constexpr const char* dBusPropertySetMethod = "Set";
109
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800110// return code: 0 successful
111int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
112{
113 std::string objpath = "/xyz/openbmc_project/FruDevice";
114 std::string intf = "xyz.openbmc_project.FruDeviceManager";
115 std::string service = getService(bus, intf, objpath);
116 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
117 if (valueTree.empty())
118 {
119 phosphor::logging::log<phosphor::logging::level::ERR>(
120 "No object implements interface",
121 phosphor::logging::entry("INTF=%s", intf.c_str()));
122 return -1;
123 }
124
Jason M. Bills64796042018-10-03 16:51:55 -0700125 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800126 {
127 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
128 if (interface == item.second.end())
129 {
130 continue;
131 }
132
133 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
134 if (property == interface->second.end())
135 {
136 continue;
137 }
138
139 try
140 {
141 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700142 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700143 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800144 {
145 phosphor::logging::log<phosphor::logging::level::ERR>(
146 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800147 return -1;
148 }
Jason M. Bills64796042018-10-03 16:51:55 -0700149 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800150 return 0;
151 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700152 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800153 {
Jason M. Bills64796042018-10-03 16:51:55 -0700154 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800155 return -1;
156 }
157 }
158 return -1;
159}
Jason M. Bills64796042018-10-03 16:51:55 -0700160
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800161// Returns the Chassis Identifier (serial #)
162ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
163 ipmi_request_t request,
164 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700165 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800166 ipmi_context_t context)
167{
168 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700169 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800170 {
Jason M. Bills64796042018-10-03 16:51:55 -0700171 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800172 return IPMI_CC_REQ_DATA_LEN_INVALID;
173 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700174 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
175 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800176 {
Jason M. Bills64796042018-10-03 16:51:55 -0700177 *dataLen = serial.size(); // length will never exceed response length
178 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700180 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800181 return IPMI_CC_OK;
182 }
Jason M. Bills64796042018-10-03 16:51:55 -0700183 *dataLen = 0;
184 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800185}
186
187ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
188 ipmi_request_t request,
189 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700190 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800191{
192 static constexpr size_t safeBufferLength = 50;
193 char buf[safeBufferLength] = {0};
194 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
195
Jason M. Bills64796042018-10-03 16:51:55 -0700196 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800197 {
Jason M. Bills64796042018-10-03 16:51:55 -0700198 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800199 return IPMI_CC_REQ_DATA_LEN_INVALID;
200 }
201
Jason M. Bills64796042018-10-03 16:51:55 -0700202 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800203
204 snprintf(
205 buf, safeBufferLength,
206 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
207 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
208 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
209 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
210 Data->node3, Data->node2, Data->node1);
211 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
212 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800213
214 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
215 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700216 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
217 std::string service = getService(*dbus, intf, objpath);
218 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800219 return IPMI_CC_OK;
220}
221
Jason M. Billsb02bf092019-08-15 13:01:56 -0700222ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
223 uint7_t reserved1)
224{
225 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
226
227 try
228 {
229 auto service =
230 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
231 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
232 bmcResetDisablesIntf, "ResetOnSMI",
233 !disableResetOnSMI);
234 }
235 catch (std::exception& e)
236 {
237 phosphor::logging::log<phosphor::logging::level::ERR>(
238 "Failed to set BMC reset disables",
239 phosphor::logging::entry("EXCEPTION=%s", e.what()));
240 return ipmi::responseUnspecifiedError();
241 }
242
243 return ipmi::responseSuccess();
244}
245
246ipmi::RspType<bool, // disableResetOnSMI
247 uint7_t // reserved
248 >
249 ipmiOEMGetBMCResetDisables()
250{
251 bool disableResetOnSMI = true;
252
253 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
254 try
255 {
256 auto service =
257 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
258 Value variant =
259 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
260 bmcResetDisablesIntf, "ResetOnSMI");
261 disableResetOnSMI = !std::get<bool>(variant);
262 }
263 catch (std::exception& e)
264 {
265 phosphor::logging::log<phosphor::logging::level::ERR>(
266 "Failed to get BMC reset disables",
267 phosphor::logging::entry("EXCEPTION=%s", e.what()));
268 return ipmi::responseUnspecifiedError();
269 }
270
271 return ipmi::responseSuccess(disableResetOnSMI, 0);
272}
273
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800274ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
275 ipmi_request_t request, ipmi_response_t response,
276 ipmi_data_len_t dataLen, ipmi_context_t context)
277{
278 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
279
Jason M. Bills64796042018-10-03 16:51:55 -0700280 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800281 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800282 *dataLen = 0;
283 return IPMI_CC_REQ_DATA_LEN_INVALID;
284 }
Jason M. Bills64796042018-10-03 16:51:55 -0700285 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800286
Vernon Mauery15419dd2019-05-24 09:40:30 -0700287 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Chalapathi899bfd12020-04-15 15:07:02 +0000288 std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath);
289 setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf,
Yong Li2742b852019-12-16 14:55:11 +0800290 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800291 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
292 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700293 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800294 *dataLen = 1;
295 return IPMI_CC_OK;
296}
297
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530298bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor,
299 uint8_t& meMajor, uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800300{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800301 // step 1 : get BMC Major and Minor numbers from its DBUS property
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530302 std::string bmcVersion;
303 if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800304 {
305 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800306 }
307
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530308 std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800309 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800310 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800311 MetaRevision revision = rev.value();
312 bmcMajor = revision.major;
313
314 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
315 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
316 }
317
318 // step 2 : get ME Major and Minor numbers from its DBUS property
AppaRao Puli32825a22020-01-17 15:52:41 +0530319 std::string meVersion;
320 if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800321 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800322 return false;
323 }
AppaRao Puli32825a22020-01-17 15:52:41 +0530324 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
325 constexpr size_t matchedPhosphor = 6;
326 std::smatch results;
327 if (std::regex_match(meVersion, results, pattern1))
328 {
329 if (results.size() == matchedPhosphor)
330 {
331 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
332 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
333 }
334 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800335 return true;
336}
337
338ipmi::RspType<
339 std::variant<std::string,
340 std::tuple<uint8_t, std::array<uint8_t, 2>,
341 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
342 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
343 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530344 ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType,
345 std::optional<uint8_t> countToRead,
AppaRao Pulid46cb422020-01-21 18:40:21 +0530346 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800347{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800348 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
349 {
350 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800351 }
352
353 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800354 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800355 {
356 case OEMDevEntityType::biosId:
357 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530358 // Byte 2&3, Only used with selecting BIOS
359 if (!countToRead || !offset)
360 {
361 return ipmi::responseReqDataLenInvalid();
362 }
363
Vernon Mauery15419dd2019-05-24 09:40:30 -0700364 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800365 std::string service =
Chalapathi899bfd12020-04-15 15:07:02 +0000366 getService(*dbus, biosVersionIntf, biosActiveObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800367 try
368 {
Yong Li2742b852019-12-16 14:55:11 +0800369 Value variant =
Chalapathi899bfd12020-04-15 15:07:02 +0000370 getDbusProperty(*dbus, service, biosActiveObjPath,
Yong Li2742b852019-12-16 14:55:11 +0800371 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700372 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530373 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800374 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800375 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800376 }
Jason M. Bills64796042018-10-03 16:51:55 -0700377 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530378 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700379 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530380 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700381 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800382 else
383 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530384 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800385 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800386
387 std::string readBuf = {0};
388 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530389 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800390 (readBuf.begin()));
391 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800392 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700393 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800394 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800395 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800396 }
397 }
398 break;
399
400 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800401 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530402 // Byte 2&3, Only used with selecting BIOS
403 if (countToRead || offset)
404 {
405 return ipmi::responseReqDataLenInvalid();
406 }
407
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800408 constexpr const size_t verLen = 2;
409 constexpr const size_t verTotalLen = 10;
410 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
411 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
412 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
413 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
414 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
415 // data0/1: BMC version number; data6/7: ME version number
416 // the others: HSC0/1/2 version number, not avaible.
AppaRao Pulie99e7ed2020-01-17 12:27:10 +0530417 if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800418 {
419 return ipmi::responseUnspecifiedError();
420 }
421 return ipmi::responseSuccess(
422 std::tuple<
423 uint8_t, std::array<uint8_t, verLen>,
424 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
425 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
426 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
427 }
428 break;
429
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800430 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800431 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530432 // Byte 2&3, Only used with selecting BIOS
433 if (countToRead || offset)
434 {
435 return ipmi::responseReqDataLenInvalid();
436 }
437
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800438 constexpr const size_t sdrLen = 2;
439 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
440 return ipmi::responseSuccess(
441 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
442 readBuf});
443 }
444 break;
445
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800446 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800447 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800448 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800449}
450
451ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
452 ipmi_request_t request, ipmi_response_t response,
453 ipmi_data_len_t dataLen, ipmi_context_t context)
454{
455 if (*dataLen != 0)
456 {
Jason M. Bills64796042018-10-03 16:51:55 -0700457 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800458 return IPMI_CC_REQ_DATA_LEN_INVALID;
459 }
460
461 *dataLen = 1;
462 uint8_t* res = reinterpret_cast<uint8_t*>(response);
463 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
464 // AIC is available so that BIOS will not timeout repeatly which leads to
465 // slow booting.
466 *res = 0; // Byte1=Count of SlotPosition/FruID records.
467 return IPMI_CC_OK;
468}
469
Jason M. Bills64796042018-10-03 16:51:55 -0700470ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
471 ipmi_request_t request,
472 ipmi_response_t response,
473 ipmi_data_len_t dataLen,
474 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800475{
Jason M. Bills64796042018-10-03 16:51:55 -0700476 GetPowerRestoreDelayRes* resp =
477 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
478
479 if (*dataLen != 0)
480 {
481 *dataLen = 0;
482 return IPMI_CC_REQ_DATA_LEN_INVALID;
483 }
484
Vernon Mauery15419dd2019-05-24 09:40:30 -0700485 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700486 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700487 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700488 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700489 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700490 powerRestoreDelayIntf, powerRestoreDelayProp);
491
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700492 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700493 resp->byteLSB = delay;
494 resp->byteMSB = delay >> 8;
495
496 *dataLen = sizeof(GetPowerRestoreDelayRes);
497
498 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800499}
500
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800501static uint8_t bcdToDec(uint8_t val)
502{
503 return ((val / 16 * 10) + (val % 16));
504}
505
506// Allows an update utility or system BIOS to send the status of an embedded
507// firmware update attempt to the BMC. After received, BMC will create a logging
508// record.
509ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
510 uint8_t majorRevision,
511 uint8_t minorRevision,
512 uint32_t auxInfo)
513{
514 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700515 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800516 target = (target & selEvtTargetMask) >> selEvtTargetShift;
517
518 /* make sure the status is 0, 1, or 2 as per the spec */
519 if (status > 2)
520 {
521 return ipmi::response(ipmi::ccInvalidFieldRequest);
522 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700523 /* make sure the target is 0, 1, 2, or 4 as per the spec */
524 if (target > 4 || target == 3)
525 {
526 return ipmi::response(ipmi::ccInvalidFieldRequest);
527 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800528 /*orignal OEM command is to record OEM SEL.
529 But openbmc does not support OEM SEL, so we redirect it to redfish event
530 logging. */
531 std::string buildInfo;
532 std::string action;
533 switch (FWUpdateTarget(target))
534 {
535 case FWUpdateTarget::targetBMC:
536 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700537 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800538 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
539 " BuildID: " + std::to_string(auxInfo);
540 buildInfo += std::to_string(auxInfo);
541 break;
542 case FWUpdateTarget::targetBIOS:
543 firmware = "BIOS";
544 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700545 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800546 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
547 " minor: " +
548 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
549 " ReleaseNumber: " + // ASCII encoded
550 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
551 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
552 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
553 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
554 break;
555 case FWUpdateTarget::targetME:
556 firmware = "ME";
557 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700558 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800559 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
560 " minor2: " +
561 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
562 " build1: " +
563 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
564 " build2: " +
565 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
566 break;
567 case FWUpdateTarget::targetOEMEWS:
568 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700569 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800570 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
571 " BuildID: " + std::to_string(auxInfo);
572 break;
573 }
574
Jason M. Billsdc249272019-04-03 09:58:40 -0700575 static const std::string openBMCMessageRegistryVersion("0.1");
576 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
577
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800578 switch (status)
579 {
580 case 0x0:
581 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700582 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800583 break;
584 case 0x1:
585 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700586 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800587 break;
588 case 0x2:
589 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700590 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800591 break;
592 default:
593 action = "unknown";
594 break;
595 }
596
Jason M. Billsdc249272019-04-03 09:58:40 -0700597 std::string firmwareInstanceStr =
598 firmware + " instance: " + std::to_string(instance);
599 std::string message("[firmware update] " + firmwareInstanceStr +
600 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800601
602 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700603 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
604 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
605 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800606 return ipmi::responseSuccess();
607}
608
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +0530609ipmi::RspType<uint8_t, std::vector<uint8_t>>
610 ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1,
611 uint2_t slotNumber, uint3_t baseBoardSlotNum,
612 uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr,
613 uint8_t netFn, uint8_t cmd,
614 std::optional<std::vector<uint8_t>> writeData)
615{
616 if (reserved1 || reserved2)
617 {
618 return ipmi::responseInvalidFieldRequest();
619 }
620
621 boost::system::error_code ec;
622 using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t,
623 std::vector<uint8_t>>;
624 ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>(
625 ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb",
626 "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb",
627 "SlotIpmbRequest", static_cast<uint8_t>(slotNumber),
628 static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd,
629 *writeData);
630 if (ec)
631 {
632 phosphor::logging::log<phosphor::logging::level::ERR>(
633 "Failed to call dbus method SlotIpmbRequest");
634 return ipmi::responseUnspecifiedError();
635 }
636
637 std::vector<uint8_t> dataReceived(0);
638 int status = -1;
639 uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0;
640
641 std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res;
642
643 if (status)
644 {
645 phosphor::logging::log<phosphor::logging::level::ERR>(
646 "Failed to get response from SlotIpmbRequest");
647 return ipmi::responseResponseError();
648 }
649 return ipmi::responseSuccess(cc, dataReceived);
650}
651
Jason M. Bills64796042018-10-03 16:51:55 -0700652ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
653 ipmi_request_t request,
654 ipmi_response_t response,
655 ipmi_data_len_t dataLen,
656 ipmi_context_t context)
657{
658 SetPowerRestoreDelayReq* data =
659 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
660 uint16_t delay = 0;
661
662 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
663 {
664 *dataLen = 0;
665 return IPMI_CC_REQ_DATA_LEN_INVALID;
666 }
667 delay = data->byteMSB;
668 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700669 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700670 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700671 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
672 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700673 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
674 *dataLen = 0;
675
676 return IPMI_CC_OK;
677}
678
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700679static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700680{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700681 static constexpr const char* cpuPresencePathPrefix =
682 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
683 static constexpr const char* cpuPresenceIntf =
684 "xyz.openbmc_project.Inventory.Item";
685 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
686 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
687 try
Jason M. Bills64796042018-10-03 16:51:55 -0700688 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700689 auto service =
690 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
691
692 ipmi::Value result = ipmi::getDbusProperty(
693 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
694 return std::get<bool>(result);
695 }
696 catch (const std::exception& e)
697 {
698 phosphor::logging::log<phosphor::logging::level::INFO>(
699 "Cannot find processor presence",
700 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
701 return false;
702 }
703}
704
705ipmi::RspType<bool, // CATERR Reset Enabled
706 bool, // ERR2 Reset Enabled
707 uint6_t, // reserved
708 uint8_t, // reserved, returns 0x3F
709 uint6_t, // CPU1 CATERR Count
710 uint2_t, // CPU1 Status
711 uint6_t, // CPU2 CATERR Count
712 uint2_t, // CPU2 Status
713 uint6_t, // CPU3 CATERR Count
714 uint2_t, // CPU3 Status
715 uint6_t, // CPU4 CATERR Count
716 uint2_t, // CPU4 Status
717 uint8_t // Crashdump Count
718 >
719 ipmiOEMGetProcessorErrConfig()
720{
721 bool resetOnCATERR = false;
722 bool resetOnERR2 = false;
723 uint6_t cpu1CATERRCount = 0;
724 uint6_t cpu2CATERRCount = 0;
725 uint6_t cpu3CATERRCount = 0;
726 uint6_t cpu4CATERRCount = 0;
727 uint8_t crashdumpCount = 0;
728 uint2_t cpu1Status =
729 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
730 uint2_t cpu2Status =
731 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
732 uint2_t cpu3Status =
733 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
734 uint2_t cpu4Status =
735 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
736
737 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
738 try
739 {
740 auto service = ipmi::getService(*busp, processorErrConfigIntf,
741 processorErrConfigObjPath);
742
743 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
744 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
745 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
746 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
747 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
748 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
749 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
750 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
751 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
752 }
753 catch (const std::exception& e)
754 {
755 phosphor::logging::log<phosphor::logging::level::ERR>(
756 "Failed to fetch processor error config",
757 phosphor::logging::entry("ERROR=%s", e.what()));
758 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700759 }
760
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700761 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
762 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
763 cpu2Status, cpu3CATERRCount, cpu3Status,
764 cpu4CATERRCount, cpu4Status, crashdumpCount);
765}
Jason M. Bills64796042018-10-03 16:51:55 -0700766
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700767ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
768 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
769 std::optional<bool> clearCPUErrorCount,
770 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
771{
772 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700773
774 try
775 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700776 auto service = ipmi::getService(*busp, processorErrConfigIntf,
777 processorErrConfigObjPath);
778 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
779 processorErrConfigIntf, "ResetOnCATERR",
780 resetOnCATERR);
781 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
782 processorErrConfigIntf, "ResetOnERR2",
783 resetOnERR2);
784 if (clearCPUErrorCount.value_or(false))
785 {
786 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700787 processorErrConfigIntf, "ErrorCountCPU1",
788 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700789 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700790 processorErrConfigIntf, "ErrorCountCPU2",
791 static_cast<uint8_t>(0));
792 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
793 processorErrConfigIntf, "ErrorCountCPU3",
794 static_cast<uint8_t>(0));
795 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
796 processorErrConfigIntf, "ErrorCountCPU4",
797 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700798 }
799 if (clearCrashdumpCount.value_or(false))
800 {
801 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700802 processorErrConfigIntf, "CrashdumpCount",
803 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700804 }
Jason M. Bills64796042018-10-03 16:51:55 -0700805 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700806 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700807 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800808 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700809 "Failed to set processor error config",
810 phosphor::logging::entry("EXCEPTION=%s", e.what()));
811 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700812 }
813
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700814 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700815}
816
Yong Li703922d2018-11-06 13:25:31 +0800817ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
818 ipmi_request_t request,
819 ipmi_response_t response,
820 ipmi_data_len_t dataLen,
821 ipmi_context_t context)
822{
823 GetOEMShutdownPolicyRes* resp =
824 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
825
826 if (*dataLen != 0)
827 {
828 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800829 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800830 *dataLen = 0;
831 return IPMI_CC_REQ_DATA_LEN_INVALID;
832 }
833
834 *dataLen = 0;
835
836 try
837 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700838 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800839 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700840 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
841 Value variant = getDbusProperty(
842 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
843 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800844
845 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
846 convertPolicyFromString(std::get<std::string>(variant)) ==
847 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
848 NoShutdownOnOCOT)
849 {
850 resp->policy = 0;
851 }
852 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
853 convertPolicyFromString(std::get<std::string>(variant)) ==
854 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
855 Policy::ShutdownOnOCOT)
856 {
857 resp->policy = 1;
858 }
859 else
860 {
861 phosphor::logging::log<phosphor::logging::level::ERR>(
862 "oem_set_shutdown_policy: invalid property!",
863 phosphor::logging::entry(
864 "PROP=%s", std::get<std::string>(variant).c_str()));
865 return IPMI_CC_UNSPECIFIED_ERROR;
866 }
Yong Li703922d2018-11-06 13:25:31 +0800867 // TODO needs to check if it is multi-node products,
868 // policy is only supported on node 3/4
869 resp->policySupport = shutdownPolicySupported;
870 }
871 catch (sdbusplus::exception_t& e)
872 {
873 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
874 return IPMI_CC_UNSPECIFIED_ERROR;
875 }
876
877 *dataLen = sizeof(GetOEMShutdownPolicyRes);
878 return IPMI_CC_OK;
879}
880
881ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
882 ipmi_request_t request,
883 ipmi_response_t response,
884 ipmi_data_len_t dataLen,
885 ipmi_context_t context)
886{
887 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800888 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
889 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
890 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800891
892 // TODO needs to check if it is multi-node products,
893 // policy is only supported on node 3/4
894 if (*dataLen != 1)
895 {
896 phosphor::logging::log<phosphor::logging::level::ERR>(
897 "oem_set_shutdown_policy: invalid input len!");
898 *dataLen = 0;
899 return IPMI_CC_REQ_DATA_LEN_INVALID;
900 }
901
902 *dataLen = 0;
903 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
904 {
905 phosphor::logging::log<phosphor::logging::level::ERR>(
906 "oem_set_shutdown_policy: invalid input!");
907 return IPMI_CC_INVALID_FIELD_REQUEST;
908 }
909
Yong Li0669d192019-05-06 14:01:46 +0800910 if (*req == noShutdownOnOCOT)
911 {
912 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
913 Policy::NoShutdownOnOCOT;
914 }
915 else
916 {
917 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
918 Policy::ShutdownOnOCOT;
919 }
920
Yong Li703922d2018-11-06 13:25:31 +0800921 try
922 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700923 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800924 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700925 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800926 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700927 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800928 oemShutdownPolicyObjPathProp,
929 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800930 }
931 catch (sdbusplus::exception_t& e)
932 {
933 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
934 return IPMI_CC_UNSPECIFIED_ERROR;
935 }
936
937 return IPMI_CC_OK;
938}
939
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530940/** @brief implementation for check the DHCP or not in IPv4
941 * @param[in] Channel - Channel number
942 * @returns true or false.
943 */
944static bool isDHCPEnabled(uint8_t Channel)
945{
946 try
947 {
948 auto ethdevice = getChannelName(Channel);
949 if (ethdevice.empty())
950 {
951 return false;
952 }
953 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700954 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530955 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700956 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
957 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530958 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700959 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530960 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
961 {
962 return true;
963 }
964 else
965 {
966 return false;
967 }
968 }
969 catch (sdbusplus::exception_t& e)
970 {
971 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
972 return true;
973 }
974}
975
976/** @brief implementes for check the DHCP or not in IPv6
977 * @param[in] Channel - Channel number
978 * @returns true or false.
979 */
980static bool isDHCPIPv6Enabled(uint8_t Channel)
981{
982
983 try
984 {
985 auto ethdevice = getChannelName(Channel);
986 if (ethdevice.empty())
987 {
988 return false;
989 }
990 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700991 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530992 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700993 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
994 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530995 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700996 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530997 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
998 {
999 return true;
1000 }
1001 else
1002 {
1003 return false;
1004 }
1005 }
1006 catch (sdbusplus::exception_t& e)
1007 {
1008 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
1009 return true;
1010 }
1011}
1012
1013/** @brief implementes the creating of default new user
1014 * @param[in] userName - new username in 16 bytes.
1015 * @param[in] userPassword - new password in 20 bytes
1016 * @returns ipmi completion code.
1017 */
1018ipmi::RspType<> ipmiOEMSetUser2Activation(
1019 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1020 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1021{
1022 bool userState = false;
1023 // Check for System Interface not exist and LAN should be static
1024 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1025 {
1026 ChannelInfo chInfo;
1027 try
1028 {
1029 getChannelInfo(channel, chInfo);
1030 }
1031 catch (sdbusplus::exception_t& e)
1032 {
1033 phosphor::logging::log<phosphor::logging::level::ERR>(
1034 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1035 phosphor::logging::entry("MSG: %s", e.description()));
1036 return ipmi::response(ipmi::ccUnspecifiedError);
1037 }
1038 if (chInfo.mediumType ==
1039 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1040 {
1041 phosphor::logging::log<phosphor::logging::level::ERR>(
1042 "ipmiOEMSetUser2Activation: system interface exist .");
1043 return ipmi::response(ipmi::ccCommandNotAvailable);
1044 }
1045 else
1046 {
1047
1048 if (chInfo.mediumType ==
1049 static_cast<uint8_t>(EChannelMediumType::lan8032))
1050 {
1051 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1052 {
1053 phosphor::logging::log<phosphor::logging::level::ERR>(
1054 "ipmiOEMSetUser2Activation: DHCP enabled .");
1055 return ipmi::response(ipmi::ccCommandNotAvailable);
1056 }
1057 }
1058 }
1059 }
1060 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1061 if (ipmi::ccSuccess ==
1062 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1063 {
1064 if (enabledUsers > 1)
1065 {
1066 phosphor::logging::log<phosphor::logging::level::ERR>(
1067 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1068 return ipmi::response(ipmi::ccCommandNotAvailable);
1069 }
1070 // Check the user 2 is enabled or not
1071 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1072 if (userState == true)
1073 {
1074 phosphor::logging::log<phosphor::logging::level::ERR>(
1075 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1076 return ipmi::response(ipmi::ccCommandNotAvailable);
1077 }
1078 }
1079 else
1080 {
1081 return ipmi::response(ipmi::ccUnspecifiedError);
1082 }
1083
1084#if BYTE_ORDER == LITTLE_ENDIAN
1085 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1086#endif
1087#if BYTE_ORDER == BIG_ENDIAN
1088 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1089#endif
1090
jayaprakash Mutyala1429d4f2020-03-04 18:20:16 +00001091 const std::string strUserName(
1092 reinterpret_cast<const char*>(userName.data()));
1093
1094 if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, strUserName))
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301095 {
1096 if (ipmi::ccSuccess ==
1097 ipmiUserSetUserPassword(
1098 ipmiDefaultUserId,
1099 reinterpret_cast<const char*>(userPassword.data())))
1100 {
1101 if (ipmi::ccSuccess ==
1102 ipmiUserSetPrivilegeAccess(
1103 ipmiDefaultUserId,
1104 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1105 privAccess, true))
1106 {
1107 phosphor::logging::log<phosphor::logging::level::INFO>(
1108 "ipmiOEMSetUser2Activation: user created successfully ");
1109 return ipmi::responseSuccess();
1110 }
1111 }
1112 // we need to delete the default user id which added in this command as
1113 // password / priv setting is failed.
1114 ipmiUserSetUserName(ipmiDefaultUserId, "");
1115 phosphor::logging::log<phosphor::logging::level::ERR>(
1116 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1117 }
1118 else
1119 {
1120 phosphor::logging::log<phosphor::logging::level::ERR>(
1121 "ipmiOEMSetUser2Activation: Setting username failed.");
1122 }
1123
1124 return ipmi::response(ipmi::ccCommandNotAvailable);
1125}
1126
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301127/** @brief implementes executing the linux command
1128 * @param[in] linux command
1129 * @returns status
1130 */
1131
1132static uint8_t executeCmd(const char* path)
1133{
1134 boost::process::child execProg(path);
1135 execProg.wait();
1136
1137 int retCode = execProg.exit_code();
1138 if (retCode)
1139 {
1140 return ipmi::ccUnspecifiedError;
1141 }
1142 return ipmi::ccSuccess;
1143}
1144
1145/** @brief implementes ASD Security event logging
1146 * @param[in] Event message string
1147 * @param[in] Event Severity
1148 * @returns status
1149 */
1150
1151static void atScaleDebugEventlog(std::string msg, int severity)
1152{
1153 std::string eventStr = "OpenBMC.0.1." + msg;
1154 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1155 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1156 eventStr.c_str(), NULL);
1157}
1158
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301159/** @brief implementes setting password for special user
1160 * @param[in] specialUserIndex
1161 * @param[in] userPassword - new password in 20 bytes
1162 * @returns ipmi completion code.
1163 */
1164ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1165 uint8_t specialUserIndex,
1166 std::vector<uint8_t> userPassword)
1167{
1168 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301169 ipmi_ret_t status = ipmi::ccSuccess;
1170
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301171 try
1172 {
1173 getChannelInfo(ctx->channel, chInfo);
1174 }
1175 catch (sdbusplus::exception_t& e)
1176 {
1177 phosphor::logging::log<phosphor::logging::level::ERR>(
1178 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1179 phosphor::logging::entry("MSG: %s", e.description()));
1180 return ipmi::responseUnspecifiedError();
1181 }
1182 if (chInfo.mediumType !=
1183 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1184 {
1185 phosphor::logging::log<phosphor::logging::level::ERR>(
1186 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1187 "interface");
1188 return ipmi::responseCommandNotAvailable();
1189 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301190
1191 // 0 for root user and 1 for AtScaleDebug is allowed
1192 if (specialUserIndex >
1193 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301194 {
1195 phosphor::logging::log<phosphor::logging::level::ERR>(
1196 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1197 return ipmi::responseParmOutOfRange();
1198 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301199 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301200 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301201 constexpr uint8_t minPasswordSizeRequired = 6;
1202 std::string passwd;
1203 if (userPassword.size() < minPasswordSizeRequired ||
1204 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1205 {
1206 return ipmi::responseReqDataLenInvalid();
1207 }
1208 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1209 userPassword.size());
1210 if (specialUserIndex ==
1211 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1212 {
1213 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1214
1215 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1216 }
1217 else
1218 {
1219 status = ipmiSetSpecialUserPassword("root", passwd);
1220 }
1221 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301222 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301223 else
1224 {
1225 if (specialUserIndex ==
1226 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1227 {
1228 status = executeCmd("passwd -d root");
1229 }
1230 else
1231 {
1232
1233 status = executeCmd("passwd -d asdbg");
1234
1235 if (status == 0)
1236 {
1237 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1238 LOG_INFO);
1239 }
1240 }
1241 return ipmi::response(status);
1242 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301243}
1244
Kuiying Wang45f04982018-12-26 09:23:08 +08001245namespace ledAction
1246{
1247using namespace sdbusplus::xyz::openbmc_project::Led::server;
1248std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001249 {Physical::Action::Off, 0},
1250 {Physical::Action::On, 2},
1251 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001252
1253std::map<uint8_t, std::string> offsetObjPath = {
1254 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1255
1256} // namespace ledAction
1257
1258int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1259 const std::string& objPath, uint8_t& state)
1260{
1261 try
1262 {
1263 std::string service = getService(bus, intf, objPath);
1264 Value stateValue =
1265 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001266 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001267 state = ledAction::actionDbusToIpmi.at(
1268 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1269 convertActionFromString(strState));
1270 }
1271 catch (sdbusplus::exception::SdBusError& e)
1272 {
1273 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1274 return -1;
1275 }
1276 return 0;
1277}
1278
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001279ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus()
Kuiying Wang45f04982018-12-26 09:23:08 +08001280{
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001281 uint8_t ledstate = 0;
Kuiying Wang45f04982018-12-26 09:23:08 +08001282 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
Vernon Mauery15419dd2019-05-24 09:40:30 -07001283 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001284 for (auto it = ledAction::offsetObjPath.begin();
1285 it != ledAction::offsetObjPath.end(); ++it)
1286 {
1287 uint8_t state = 0;
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001288 if (getLEDState(*dbus, ledIntf, it->second, state) == -1)
Kuiying Wang45f04982018-12-26 09:23:08 +08001289 {
1290 phosphor::logging::log<phosphor::logging::level::ERR>(
1291 "oem_get_led_status: fail to get ID LED status!");
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001292 return ipmi::responseUnspecifiedError();
Kuiying Wang45f04982018-12-26 09:23:08 +08001293 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001294 ledstate |= state << it->first;
Kuiying Wang45f04982018-12-26 09:23:08 +08001295 }
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00001296 return ipmi::responseSuccess(ledstate);
Kuiying Wang45f04982018-12-26 09:23:08 +08001297}
1298
Yong Li23737fe2019-02-19 08:49:55 +08001299ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1300 ipmi_request_t request,
1301 ipmi_response_t response,
1302 ipmi_data_len_t dataLen,
1303 ipmi_context_t context)
1304{
1305 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1306 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1307
1308 if (*dataLen == 0)
1309 {
1310 phosphor::logging::log<phosphor::logging::level::ERR>(
1311 "CfgHostSerial: invalid input len!",
1312 phosphor::logging::entry("LEN=%d", *dataLen));
1313 return IPMI_CC_REQ_DATA_LEN_INVALID;
1314 }
1315
1316 switch (req->command)
1317 {
1318 case getHostSerialCfgCmd:
1319 {
1320 if (*dataLen != 1)
1321 {
1322 phosphor::logging::log<phosphor::logging::level::ERR>(
1323 "CfgHostSerial: invalid input len!");
1324 *dataLen = 0;
1325 return IPMI_CC_REQ_DATA_LEN_INVALID;
1326 }
1327
1328 *dataLen = 0;
1329
1330 boost::process::ipstream is;
1331 std::vector<std::string> data;
1332 std::string line;
1333 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1334 boost::process::std_out > is);
1335
1336 while (c1.running() && std::getline(is, line) && !line.empty())
1337 {
1338 data.push_back(line);
1339 }
1340
1341 c1.wait();
1342 if (c1.exit_code())
1343 {
1344 phosphor::logging::log<phosphor::logging::level::ERR>(
1345 "CfgHostSerial:: error on execute",
1346 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1347 // Using the default value
1348 *resp = 0;
1349 }
1350 else
1351 {
1352 if (data.size() != 1)
1353 {
1354 phosphor::logging::log<phosphor::logging::level::ERR>(
1355 "CfgHostSerial:: error on read env");
1356 return IPMI_CC_UNSPECIFIED_ERROR;
1357 }
1358 try
1359 {
1360 unsigned long tmp = std::stoul(data[0]);
1361 if (tmp > std::numeric_limits<uint8_t>::max())
1362 {
1363 throw std::out_of_range("Out of range");
1364 }
1365 *resp = static_cast<uint8_t>(tmp);
1366 }
1367 catch (const std::invalid_argument& e)
1368 {
1369 phosphor::logging::log<phosphor::logging::level::ERR>(
1370 "invalid config ",
1371 phosphor::logging::entry("ERR=%s", e.what()));
1372 return IPMI_CC_UNSPECIFIED_ERROR;
1373 }
1374 catch (const std::out_of_range& e)
1375 {
1376 phosphor::logging::log<phosphor::logging::level::ERR>(
1377 "out_of_range config ",
1378 phosphor::logging::entry("ERR=%s", e.what()));
1379 return IPMI_CC_UNSPECIFIED_ERROR;
1380 }
1381 }
1382
1383 *dataLen = 1;
1384 break;
1385 }
1386 case setHostSerialCfgCmd:
1387 {
1388 if (*dataLen != sizeof(CfgHostSerialReq))
1389 {
1390 phosphor::logging::log<phosphor::logging::level::ERR>(
1391 "CfgHostSerial: invalid input len!");
1392 *dataLen = 0;
1393 return IPMI_CC_REQ_DATA_LEN_INVALID;
1394 }
1395
1396 *dataLen = 0;
1397
1398 if (req->parameter > HostSerialCfgParamMax)
1399 {
1400 phosphor::logging::log<phosphor::logging::level::ERR>(
1401 "CfgHostSerial: invalid input!");
1402 return IPMI_CC_INVALID_FIELD_REQUEST;
1403 }
1404
1405 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1406 std::to_string(req->parameter));
1407
1408 c1.wait();
1409 if (c1.exit_code())
1410 {
1411 phosphor::logging::log<phosphor::logging::level::ERR>(
1412 "CfgHostSerial:: error on execute",
1413 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1414 return IPMI_CC_UNSPECIFIED_ERROR;
1415 }
1416 break;
1417 }
1418 default:
1419 phosphor::logging::log<phosphor::logging::level::ERR>(
1420 "CfgHostSerial: invalid input!");
1421 *dataLen = 0;
1422 return IPMI_CC_INVALID_FIELD_REQUEST;
1423 }
1424
1425 return IPMI_CC_OK;
1426}
1427
James Feist91244a62019-02-19 15:04:54 -08001428constexpr const char* thermalModeInterface =
1429 "xyz.openbmc_project.Control.ThermalMode";
1430constexpr const char* thermalModePath =
1431 "/xyz/openbmc_project/control/thermal_mode";
1432
1433bool getFanProfileInterface(
1434 sdbusplus::bus::bus& bus,
1435 boost::container::flat_map<
1436 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1437{
1438 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1439 "GetAll");
1440 call.append(thermalModeInterface);
1441 try
1442 {
1443 auto data = bus.call(call);
1444 data.read(resp);
1445 }
1446 catch (sdbusplus::exception_t& e)
1447 {
1448 phosphor::logging::log<phosphor::logging::level::ERR>(
1449 "getFanProfileInterface: can't get thermal mode!",
1450 phosphor::logging::entry("ERR=%s", e.what()));
1451 return false;
1452 }
1453 return true;
1454}
1455
anil kumar appanaf945eee2019-09-25 23:29:11 +00001456/**@brief implements the OEM set fan config.
1457 * @param selectedFanProfile - fan profile to enable
1458 * @param reserved1
1459 * @param performanceMode - Performance/Acoustic mode
1460 * @param reserved2
1461 * @param setPerformanceMode - set Performance/Acoustic mode
1462 * @param setFanProfile - set fan profile
1463 *
1464 * @return IPMI completion code.
1465 **/
1466ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1467
1468 uint2_t reserved1, bool performanceMode,
1469 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301470 bool setFanProfile,
1471 std::optional<uint8_t> dimmGroupId,
1472 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001473{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001474 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001475 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001476 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001477 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301478
1479 if (dimmGroupId)
1480 {
1481 if (*dimmGroupId >= maxCPUNum)
1482 {
1483 return ipmi::responseInvalidFieldRequest();
1484 }
1485 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1486 {
1487 return ipmi::responseInvalidFieldRequest();
1488 }
1489 }
1490
James Feist91244a62019-02-19 15:04:54 -08001491 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001492 boost::container::flat_map<
1493 std::string, std::variant<std::vector<std::string>, std::string>>
1494 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001495 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1496 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001497 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001498 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001499 }
1500
1501 std::vector<std::string>* supported =
1502 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1503 if (supported == nullptr)
1504 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001505 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001506 }
1507 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001508 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001509 {
James Feist91244a62019-02-19 15:04:54 -08001510 if (performanceMode)
1511 {
1512
1513 if (std::find(supported->begin(), supported->end(),
1514 "Performance") != supported->end())
1515 {
1516 mode = "Performance";
1517 }
1518 }
1519 else
1520 {
James Feist91244a62019-02-19 15:04:54 -08001521 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1522 supported->end())
1523 {
1524 mode = "Acoustic";
1525 }
1526 }
1527 if (mode.empty())
1528 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001529 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001530 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001531
1532 try
1533 {
1534 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1535 thermalModeInterface, "Current", mode);
1536 }
1537 catch (sdbusplus::exception_t& e)
1538 {
1539 phosphor::logging::log<phosphor::logging::level::ERR>(
1540 "ipmiOEMSetFanConfig: can't set thermal mode!",
1541 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1542 return ipmi::responseResponseError();
1543 }
James Feist91244a62019-02-19 15:04:54 -08001544 }
1545
anil kumar appanaf945eee2019-09-25 23:29:11 +00001546 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001547}
1548
James Feist5b693632019-07-09 09:06:09 -07001549ipmi::RspType<uint8_t, // profile support map
1550 uint8_t, // fan control profile enable
1551 uint8_t, // flags
1552 uint32_t // dimm presence bit map
1553 >
1554 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001555{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301556 if (dimmGroupId >= maxCPUNum)
1557 {
1558 return ipmi::responseInvalidFieldRequest();
1559 }
1560
1561 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1562
1563 if (!cpuStatus)
1564 {
1565 return ipmi::responseInvalidFieldRequest();
1566 }
1567
James Feist91244a62019-02-19 15:04:54 -08001568 boost::container::flat_map<
1569 std::string, std::variant<std::vector<std::string>, std::string>>
1570 profileData;
1571
Vernon Mauery15419dd2019-05-24 09:40:30 -07001572 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1573 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001574 {
James Feist5b693632019-07-09 09:06:09 -07001575 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001576 }
1577
1578 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1579
1580 if (current == nullptr)
1581 {
1582 phosphor::logging::log<phosphor::logging::level::ERR>(
1583 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001584 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001585 }
1586 bool performance = (*current == "Performance");
1587
James Feist5b693632019-07-09 09:06:09 -07001588 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001589 if (performance)
1590 {
James Feist5b693632019-07-09 09:06:09 -07001591 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001592 }
1593
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001594 constexpr uint8_t fanControlDefaultProfile = 0x80;
1595 constexpr uint8_t fanControlProfileState = 0x00;
1596 constexpr uint32_t dimmPresenceBitmap = 0x00;
1597
1598 return ipmi::responseSuccess(fanControlDefaultProfile,
1599 fanControlProfileState, flags,
1600 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001601}
James Feist5f957ca2019-03-14 15:33:55 -07001602constexpr const char* cfmLimitSettingPath =
1603 "/xyz/openbmc_project/control/cfm_limit";
1604constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001605constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001606constexpr const size_t legacyPCHSensorNumber = 0x22;
1607constexpr const char* exitAirPathName = "Exit_Air";
1608constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001609constexpr const char* pidConfigurationIface =
1610 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001611
James Feist09f6b602019-08-08 11:30:03 -07001612static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001613{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001614 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001615 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001616 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1617 "/xyz/openbmc_project/object_mapper",
1618 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001619
James Feistacc8a4e2019-04-02 14:23:57 -07001620 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001621 std::string path;
1622 GetSubTreeType resp;
1623 try
1624 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001625 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001626 reply.read(resp);
1627 }
1628 catch (sdbusplus::exception_t&)
1629 {
1630 phosphor::logging::log<phosphor::logging::level::ERR>(
1631 "ipmiOEMGetFscParameter: mapper error");
1632 };
James Feist09f6b602019-08-08 11:30:03 -07001633 auto config =
1634 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1635 return pair.first.find(name) != std::string::npos;
1636 });
James Feistfaa4f222019-03-21 16:21:55 -07001637 if (config != resp.end())
1638 {
1639 path = std::move(config->first);
1640 }
1641 return path;
1642}
James Feist5f957ca2019-03-14 15:33:55 -07001643
James Feistacc8a4e2019-04-02 14:23:57 -07001644// flat map to make alphabetical
1645static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1646{
1647 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001648 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001649 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001650 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1651 "/xyz/openbmc_project/object_mapper",
1652 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001653
1654 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1655 GetSubTreeType resp;
1656
1657 try
1658 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001659 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001660 reply.read(resp);
1661 }
1662 catch (sdbusplus::exception_t&)
1663 {
1664 phosphor::logging::log<phosphor::logging::level::ERR>(
1665 "getFanConfigPaths: mapper error");
1666 };
1667 for (const auto& [path, objects] : resp)
1668 {
1669 if (objects.empty())
1670 {
1671 continue; // should be impossible
1672 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001673
1674 try
1675 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001676 ret.emplace(path,
1677 getAllDbusProperties(*dbus, objects[0].first, path,
1678 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001679 }
1680 catch (sdbusplus::exception_t& e)
1681 {
1682 phosphor::logging::log<phosphor::logging::level::ERR>(
1683 "getPidConfigs: can't get DbusProperties!",
1684 phosphor::logging::entry("ERR=%s", e.what()));
1685 }
James Feistacc8a4e2019-04-02 14:23:57 -07001686 }
1687 return ret;
1688}
1689
1690ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1691{
1692 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1693 if (data.empty())
1694 {
1695 return ipmi::responseResponseError();
1696 }
1697 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1698 for (const auto& [_, pid] : data)
1699 {
1700 auto findClass = pid.find("Class");
1701 if (findClass == pid.end())
1702 {
1703 phosphor::logging::log<phosphor::logging::level::ERR>(
1704 "ipmiOEMGetFscParameter: found illegal pid "
1705 "configurations");
1706 return ipmi::responseResponseError();
1707 }
1708 std::string type = std::get<std::string>(findClass->second);
1709 if (type == "fan")
1710 {
1711 auto findOutLimit = pid.find("OutLimitMin");
1712 if (findOutLimit == pid.end())
1713 {
1714 phosphor::logging::log<phosphor::logging::level::ERR>(
1715 "ipmiOEMGetFscParameter: found illegal pid "
1716 "configurations");
1717 return ipmi::responseResponseError();
1718 }
1719 // get the min out of all the offsets
1720 minOffset = std::min(
1721 minOffset,
1722 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1723 }
1724 }
1725 if (minOffset == std::numeric_limits<uint8_t>::max())
1726 {
1727 phosphor::logging::log<phosphor::logging::level::ERR>(
1728 "ipmiOEMGetFscParameter: found no fan configurations!");
1729 return ipmi::responseResponseError();
1730 }
1731
1732 return ipmi::responseSuccess(minOffset);
1733}
1734
1735ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1736{
1737 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1738 if (data.empty())
1739 {
1740
1741 phosphor::logging::log<phosphor::logging::level::ERR>(
1742 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1743 return ipmi::responseResponseError();
1744 }
1745
Vernon Mauery15419dd2019-05-24 09:40:30 -07001746 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001747 bool found = false;
1748 for (const auto& [path, pid] : data)
1749 {
1750 auto findClass = pid.find("Class");
1751 if (findClass == pid.end())
1752 {
1753
1754 phosphor::logging::log<phosphor::logging::level::ERR>(
1755 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1756 "configurations");
1757 return ipmi::responseResponseError();
1758 }
1759 std::string type = std::get<std::string>(findClass->second);
1760 if (type == "fan")
1761 {
1762 auto findOutLimit = pid.find("OutLimitMin");
1763 if (findOutLimit == pid.end())
1764 {
1765
1766 phosphor::logging::log<phosphor::logging::level::ERR>(
1767 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1768 "configurations");
1769 return ipmi::responseResponseError();
1770 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001771 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001772 path, pidConfigurationIface, "OutLimitMin",
1773 static_cast<double>(offset));
1774 found = true;
1775 }
1776 }
1777 if (!found)
1778 {
1779 phosphor::logging::log<phosphor::logging::level::ERR>(
1780 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1781 return ipmi::responseResponseError();
1782 }
1783
1784 return ipmi::responseSuccess();
1785}
1786
1787ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1788 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001789{
1790 constexpr const size_t disableLimiting = 0x0;
1791
Vernon Mauery15419dd2019-05-24 09:40:30 -07001792 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001793 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001794 {
James Feist09f6b602019-08-08 11:30:03 -07001795 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001796 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001797 {
James Feist09f6b602019-08-08 11:30:03 -07001798 pathName = exitAirPathName;
1799 }
1800 else if (param1 == legacyPCHSensorNumber)
1801 {
1802 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001803 }
1804 else
1805 {
James Feistacc8a4e2019-04-02 14:23:57 -07001806 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001807 }
James Feist09f6b602019-08-08 11:30:03 -07001808 std::string path = getConfigPath(pathName);
1809 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1810 pidConfigurationIface, "SetPoint",
1811 static_cast<double>(param2));
1812 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001813 }
James Feistacc8a4e2019-04-02 14:23:57 -07001814 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001815 {
James Feistacc8a4e2019-04-02 14:23:57 -07001816 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001817
1818 // must be greater than 50 based on eps
1819 if (cfm < 50 && cfm != disableLimiting)
1820 {
James Feistacc8a4e2019-04-02 14:23:57 -07001821 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001822 }
1823
1824 try
1825 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001826 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001827 cfmLimitIface, "Limit",
1828 static_cast<double>(cfm));
1829 }
1830 catch (sdbusplus::exception_t& e)
1831 {
1832 phosphor::logging::log<phosphor::logging::level::ERR>(
1833 "ipmiOEMSetFscParameter: can't set cfm setting!",
1834 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001835 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001836 }
James Feistacc8a4e2019-04-02 14:23:57 -07001837 return ipmi::responseSuccess();
1838 }
1839 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1840 {
1841 constexpr const size_t maxDomainCount = 8;
1842 uint8_t requestedDomainMask = param1;
1843 boost::container::flat_map data = getPidConfigs();
1844 if (data.empty())
1845 {
1846
1847 phosphor::logging::log<phosphor::logging::level::ERR>(
1848 "ipmiOEMSetFscParameter: found no pid configurations!");
1849 return ipmi::responseResponseError();
1850 }
1851 size_t count = 0;
1852 for (const auto& [path, pid] : data)
1853 {
1854 auto findClass = pid.find("Class");
1855 if (findClass == pid.end())
1856 {
1857
1858 phosphor::logging::log<phosphor::logging::level::ERR>(
1859 "ipmiOEMSetFscParameter: found illegal pid "
1860 "configurations");
1861 return ipmi::responseResponseError();
1862 }
1863 std::string type = std::get<std::string>(findClass->second);
1864 if (type == "fan")
1865 {
1866 if (requestedDomainMask & (1 << count))
1867 {
1868 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001869 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001870 pidConfigurationIface, "OutLimitMax",
1871 static_cast<double>(param2));
1872 }
1873 count++;
1874 }
1875 }
1876 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001877 }
1878 else
1879 {
1880 // todo other command parts possibly
1881 // tcontrol is handled in peci now
1882 // fan speed offset not implemented yet
1883 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001884 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001885 }
1886}
1887
James Feistacc8a4e2019-04-02 14:23:57 -07001888ipmi::RspType<
1889 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1890 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001891{
James Feist09f6b602019-08-08 11:30:03 -07001892 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001893
Vernon Mauery15419dd2019-05-24 09:40:30 -07001894 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001895 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001896 {
James Feistacc8a4e2019-04-02 14:23:57 -07001897 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001898 {
James Feistacc8a4e2019-04-02 14:23:57 -07001899 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001900 }
1901
James Feist09f6b602019-08-08 11:30:03 -07001902 std::string pathName;
1903
1904 if (*param == legacyExitAirSensorNumber)
1905 {
1906 pathName = exitAirPathName;
1907 }
1908 else if (*param == legacyPCHSensorNumber)
1909 {
1910 pathName = pchPathName;
1911 }
1912 else
James Feistfaa4f222019-03-21 16:21:55 -07001913 {
James Feistacc8a4e2019-04-02 14:23:57 -07001914 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001915 }
James Feist09f6b602019-08-08 11:30:03 -07001916
1917 uint8_t setpoint = legacyDefaultSetpoint;
1918 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001919 if (path.size())
1920 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001921 Value val = ipmi::getDbusProperty(
1922 *dbus, "xyz.openbmc_project.EntityManager", path,
1923 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001924 setpoint = std::floor(std::get<double>(val) + 0.5);
1925 }
1926
1927 // old implementation used to return the "default" and current, we
1928 // don't make the default readily available so just make both the
1929 // same
James Feistfaa4f222019-03-21 16:21:55 -07001930
James Feistacc8a4e2019-04-02 14:23:57 -07001931 return ipmi::responseSuccess(
1932 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001933 }
James Feistacc8a4e2019-04-02 14:23:57 -07001934 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1935 {
1936 constexpr const size_t maxDomainCount = 8;
1937
1938 if (!param)
1939 {
1940 return ipmi::responseReqDataLenInvalid();
1941 }
1942 uint8_t requestedDomain = *param;
1943 if (requestedDomain >= maxDomainCount)
1944 {
1945 return ipmi::responseInvalidFieldRequest();
1946 }
1947
1948 boost::container::flat_map data = getPidConfigs();
1949 if (data.empty())
1950 {
1951 phosphor::logging::log<phosphor::logging::level::ERR>(
1952 "ipmiOEMGetFscParameter: found no pid configurations!");
1953 return ipmi::responseResponseError();
1954 }
1955 size_t count = 0;
1956 for (const auto& [_, pid] : data)
1957 {
1958 auto findClass = pid.find("Class");
1959 if (findClass == pid.end())
1960 {
1961 phosphor::logging::log<phosphor::logging::level::ERR>(
1962 "ipmiOEMGetFscParameter: found illegal pid "
1963 "configurations");
1964 return ipmi::responseResponseError();
1965 }
1966 std::string type = std::get<std::string>(findClass->second);
1967 if (type == "fan")
1968 {
1969 if (requestedDomain == count)
1970 {
1971 auto findOutLimit = pid.find("OutLimitMax");
1972 if (findOutLimit == pid.end())
1973 {
1974 phosphor::logging::log<phosphor::logging::level::ERR>(
1975 "ipmiOEMGetFscParameter: found illegal pid "
1976 "configurations");
1977 return ipmi::responseResponseError();
1978 }
1979
1980 return ipmi::responseSuccess(
1981 static_cast<uint8_t>(std::floor(
1982 std::get<double>(findOutLimit->second) + 0.5)));
1983 }
1984 else
1985 {
1986 count++;
1987 }
1988 }
1989 }
1990
1991 return ipmi::responseInvalidFieldRequest();
1992 }
1993 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001994 {
1995
1996 /*
1997 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001998 previous behavior didn't seem to prevent this, ignore the check for
1999 now.
James Feist5f957ca2019-03-14 15:33:55 -07002000
James Feistacc8a4e2019-04-02 14:23:57 -07002001 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07002002 {
2003 phosphor::logging::log<phosphor::logging::level::ERR>(
2004 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07002005 return IPMI_CC_REQ_DATA_LEN_INVALID;
2006 }
2007 */
2008 Value cfmLimit;
2009 Value cfmMaximum;
2010 try
2011 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002012 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07002013 cfmLimitSettingPath, cfmLimitIface,
2014 "Limit");
2015 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002016 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002017 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2018 }
2019 catch (sdbusplus::exception_t& e)
2020 {
2021 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002022 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002023 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002024 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002025 }
2026
James Feistacc8a4e2019-04-02 14:23:57 -07002027 double cfmMax = std::get<double>(cfmMaximum);
2028 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002029
James Feistacc8a4e2019-04-02 14:23:57 -07002030 cfmLim = std::floor(cfmLim + 0.5);
2031 cfmMax = std::floor(cfmMax + 0.5);
2032 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2033 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002034
James Feistacc8a4e2019-04-02 14:23:57 -07002035 return ipmi::responseSuccess(
2036 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002037 }
James Feistacc8a4e2019-04-02 14:23:57 -07002038
James Feist5f957ca2019-03-14 15:33:55 -07002039 else
2040 {
2041 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002042 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002043 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002044 }
2045}
2046
Cheng C Yang773703a2019-08-15 09:41:11 +08002047using crConfigVariant =
2048 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2049
2050int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2051 const crConfigVariant& value,
2052 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2053{
2054 boost::system::error_code ec;
2055 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002056 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002057 "/xyz/openbmc_project/control/power_supply_redundancy",
2058 "org.freedesktop.DBus.Properties", "Set",
2059 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2060 if (ec)
2061 {
2062 phosphor::logging::log<phosphor::logging::level::ERR>(
2063 "Failed to set dbus property to cold redundancy");
2064 return -1;
2065 }
2066
2067 return 0;
2068}
2069
2070int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2071 crConfigVariant& value,
Yong Li19445ab2019-12-20 18:25:29 +08002072 const std::string& service = "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002073 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2074{
2075 boost::system::error_code ec;
2076 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002077 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002078 "/xyz/openbmc_project/control/power_supply_redundancy",
2079 "org.freedesktop.DBus.Properties", "Get",
2080 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2081 if (ec)
2082 {
2083 phosphor::logging::log<phosphor::logging::level::ERR>(
2084 "Failed to get dbus property to cold redundancy");
2085 return -1;
2086 }
2087 return 0;
2088}
2089
2090uint8_t getPSUCount(void)
2091{
2092 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2093 ipmi::Value num;
2094 try
2095 {
2096 num = ipmi::getDbusProperty(
2097 *dbus, "xyz.openbmc_project.PSURedundancy",
2098 "/xyz/openbmc_project/control/power_supply_redundancy",
2099 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2100 }
2101 catch (sdbusplus::exception_t& e)
2102 {
2103 phosphor::logging::log<phosphor::logging::level::ERR>(
2104 "Failed to get PSUNumber property from dbus interface");
2105 return 0;
2106 }
2107 uint8_t* pNum = std::get_if<uint8_t>(&num);
2108 if (!pNum)
2109 {
2110 phosphor::logging::log<phosphor::logging::level::ERR>(
2111 "Error to get PSU Number");
2112 return 0;
2113 }
2114 return *pNum;
2115}
2116
2117bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2118{
2119 if (conf.size() < num)
2120 {
2121 phosphor::logging::log<phosphor::logging::level::ERR>(
2122 "Invalid PSU Ranking");
2123 return false;
2124 }
2125 std::set<uint8_t> confSet;
2126 for (uint8_t i = 0; i < num; i++)
2127 {
2128 if (conf[i] > num)
2129 {
2130 phosphor::logging::log<phosphor::logging::level::ERR>(
2131 "PSU Ranking is larger than current PSU number");
2132 return false;
2133 }
2134 confSet.emplace(conf[i]);
2135 }
2136
2137 if (confSet.size() != num)
2138 {
2139 phosphor::logging::log<phosphor::logging::level::ERR>(
2140 "duplicate PSU Ranking");
2141 return false;
2142 }
2143 return true;
2144}
2145
2146enum class crParameter
2147{
2148 crStatus = 0,
2149 crFeature = 1,
2150 rotationFeature = 2,
2151 rotationAlgo = 3,
2152 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002153 numOfPSU = 5,
2154 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002155};
2156
2157constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2158static const constexpr uint32_t oneDay = 0x15180;
2159static const constexpr uint32_t oneMonth = 0xf53700;
2160static const constexpr uint8_t userSpecific = 0x01;
2161static const constexpr uint8_t crSetCompleted = 0;
2162ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2163 uint8_t parameter,
2164 ipmi::message::Payload& payload)
2165{
2166 switch (static_cast<crParameter>(parameter))
2167 {
2168 case crParameter::crFeature:
2169 {
2170 uint8_t param1;
2171 if (payload.unpack(param1) || !payload.fullyUnpacked())
2172 {
2173 return ipmi::responseReqDataLenInvalid();
2174 }
2175 // ColdRedundancy Enable can only be true or flase
2176 if (param1 > 1)
2177 {
2178 return ipmi::responseInvalidFieldRequest();
2179 }
2180 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2181 static_cast<bool>(param1)))
2182 {
2183 return ipmi::responseResponseError();
2184 }
2185 break;
2186 }
2187 case crParameter::rotationFeature:
2188 {
2189 uint8_t param1;
2190 if (payload.unpack(param1) || !payload.fullyUnpacked())
2191 {
2192 return ipmi::responseReqDataLenInvalid();
2193 }
2194 // Rotation Enable can only be true or false
2195 if (param1 > 1)
2196 {
2197 return ipmi::responseInvalidFieldRequest();
2198 }
2199 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2200 {
2201 return ipmi::responseResponseError();
2202 }
2203 break;
2204 }
2205 case crParameter::rotationAlgo:
2206 {
2207 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2208 std::string algoName;
2209 uint8_t param1;
2210 if (payload.unpack(param1))
2211 {
2212 return ipmi::responseReqDataLenInvalid();
2213 }
2214 switch (param1)
2215 {
2216 case 0:
2217 algoName = "xyz.openbmc_project.Control."
2218 "PowerSupplyRedundancy.Algo.bmcSpecific";
2219 break;
2220 case 1:
2221 algoName = "xyz.openbmc_project.Control."
2222 "PowerSupplyRedundancy.Algo.userSpecific";
2223 break;
2224 default:
2225 return ipmi::responseInvalidFieldRequest();
2226 }
2227 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2228 {
2229 return ipmi::responseResponseError();
2230 }
2231
2232 uint8_t numberOfPSU = getPSUCount();
2233 if (!numberOfPSU)
2234 {
2235 return ipmi::responseResponseError();
2236 }
2237 std::vector<uint8_t> rankOrder;
2238
2239 if (param1 == userSpecific)
2240 {
2241 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2242 {
2243 ipmi::responseReqDataLenInvalid();
2244 }
Yong Li83315132019-10-23 17:42:24 +08002245 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002246 {
2247 return ipmi::responseReqDataLenInvalid();
2248 }
2249
2250 if (!validateCRAlgo(rankOrder, numberOfPSU))
2251 {
2252 return ipmi::responseInvalidFieldRequest();
2253 }
2254 }
2255 else
2256 {
2257 if (rankOrder.size() > 0)
2258 {
2259 return ipmi::responseReqDataLenInvalid();
2260 }
2261 for (uint8_t i = 1; i <= numberOfPSU; i++)
2262 {
2263 rankOrder.emplace_back(i);
2264 }
2265 }
2266 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2267 {
2268 return ipmi::responseResponseError();
2269 }
2270 break;
2271 }
2272 case crParameter::rotationPeriod:
2273 {
2274 // Minimum Rotation period is One day (86400 seconds) and Max
2275 // Rotation Period is 6 month (0xf53700 seconds)
2276 uint32_t period;
2277 if (payload.unpack(period) || !payload.fullyUnpacked())
2278 {
2279 return ipmi::responseReqDataLenInvalid();
2280 }
2281 if ((period < oneDay) || (period > oneMonth))
2282 {
2283 return ipmi::responseInvalidFieldRequest();
2284 }
2285 if (setCRConfig(ctx, "PeriodOfRotation", period))
2286 {
2287 return ipmi::responseResponseError();
2288 }
2289 break;
2290 }
2291 default:
2292 {
2293 return ipmi::response(ccParameterNotSupported);
2294 }
2295 }
2296
2297 // TODO Halfwidth needs to set SetInProgress
2298 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002299 std::string("xyz.openbmc_project.Control."
2300 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002301 {
2302 return ipmi::responseResponseError();
2303 }
2304 return ipmi::responseSuccess(crSetCompleted);
2305}
2306
Yong Li83315132019-10-23 17:42:24 +08002307ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002308 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2309{
2310 crConfigVariant value;
2311 switch (static_cast<crParameter>(parameter))
2312 {
2313 case crParameter::crStatus:
2314 {
2315 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2316 {
2317 return ipmi::responseResponseError();
2318 }
2319 std::string* pStatus = std::get_if<std::string>(&value);
2320 if (!pStatus)
2321 {
2322 phosphor::logging::log<phosphor::logging::level::ERR>(
2323 "Error to get ColdRedundancyStatus property");
2324 return ipmi::responseResponseError();
2325 }
2326 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2327 auto status =
2328 server::PowerSupplyRedundancy::convertStatusFromString(
2329 *pStatus);
2330 switch (status)
2331 {
2332 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002333 return ipmi::responseSuccess(parameter,
2334 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002335
2336 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002337 return ipmi::responseSuccess(parameter,
2338 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002339 default:
2340 phosphor::logging::log<phosphor::logging::level::ERR>(
2341 "Error to get valid status");
2342 return ipmi::responseResponseError();
2343 }
2344 }
2345 case crParameter::crFeature:
2346 {
2347 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2348 {
2349 return ipmi::responseResponseError();
2350 }
2351 bool* pResponse = std::get_if<bool>(&value);
2352 if (!pResponse)
2353 {
2354 phosphor::logging::log<phosphor::logging::level::ERR>(
2355 "Error to get ColdRedundancyEnable property");
2356 return ipmi::responseResponseError();
2357 }
2358
Cheng C Yangf41e3342019-09-10 04:47:23 +08002359 return ipmi::responseSuccess(parameter,
2360 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002361 }
2362 case crParameter::rotationFeature:
2363 {
2364 if (getCRConfig(ctx, "RotationEnabled", value))
2365 {
2366 return ipmi::responseResponseError();
2367 }
2368 bool* pResponse = std::get_if<bool>(&value);
2369 if (!pResponse)
2370 {
2371 phosphor::logging::log<phosphor::logging::level::ERR>(
2372 "Error to get RotationEnabled property");
2373 return ipmi::responseResponseError();
2374 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002375 return ipmi::responseSuccess(parameter,
2376 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002377 }
2378 case crParameter::rotationAlgo:
2379 {
2380 if (getCRConfig(ctx, "RotationAlgorithm", value))
2381 {
2382 return ipmi::responseResponseError();
2383 }
2384
2385 std::string* pAlgo = std::get_if<std::string>(&value);
2386 if (!pAlgo)
2387 {
2388 phosphor::logging::log<phosphor::logging::level::ERR>(
2389 "Error to get RotationAlgorithm property");
2390 return ipmi::responseResponseError();
2391 }
Yong Li83315132019-10-23 17:42:24 +08002392 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002393 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2394 auto algo =
2395 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002396
Cheng C Yang773703a2019-08-15 09:41:11 +08002397 switch (algo)
2398 {
2399 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002400 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002401 break;
2402 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002403 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002404 break;
2405 default:
2406 phosphor::logging::log<phosphor::logging::level::ERR>(
2407 "Error to get valid algo");
2408 return ipmi::responseResponseError();
2409 }
2410
2411 if (getCRConfig(ctx, "RotationRankOrder", value))
2412 {
2413 return ipmi::responseResponseError();
2414 }
2415 std::vector<uint8_t>* pResponse =
2416 std::get_if<std::vector<uint8_t>>(&value);
2417 if (!pResponse)
2418 {
2419 phosphor::logging::log<phosphor::logging::level::ERR>(
2420 "Error to get RotationRankOrder property");
2421 return ipmi::responseResponseError();
2422 }
Yong Li83315132019-10-23 17:42:24 +08002423
Cheng C Yang773703a2019-08-15 09:41:11 +08002424 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002425 std::back_inserter(response));
2426
Cheng C Yangf41e3342019-09-10 04:47:23 +08002427 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002428 }
2429 case crParameter::rotationPeriod:
2430 {
2431 if (getCRConfig(ctx, "PeriodOfRotation", value))
2432 {
2433 return ipmi::responseResponseError();
2434 }
2435 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2436 if (!pResponse)
2437 {
2438 phosphor::logging::log<phosphor::logging::level::ERR>(
2439 "Error to get RotationAlgorithm property");
2440 return ipmi::responseResponseError();
2441 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002442 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002443 }
2444 case crParameter::numOfPSU:
2445 {
2446 uint8_t numberOfPSU = getPSUCount();
2447 if (!numberOfPSU)
2448 {
2449 return ipmi::responseResponseError();
2450 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002451 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002452 }
Yong Li19445ab2019-12-20 18:25:29 +08002453 case crParameter::rotationRankOrderEffective:
2454 {
2455 if (getCRConfig(ctx, "RotationRankOrder", value,
2456 "xyz.openbmc_project.PSURedundancy"))
2457 {
2458 return ipmi::responseResponseError();
2459 }
2460 std::vector<uint8_t>* pResponse =
2461 std::get_if<std::vector<uint8_t>>(&value);
2462 if (!pResponse)
2463 {
2464 phosphor::logging::log<phosphor::logging::level::ERR>(
2465 "Error to get effective RotationRankOrder property");
2466 return ipmi::responseResponseError();
2467 }
2468 return ipmi::responseSuccess(parameter, *pResponse);
2469 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002470 default:
2471 {
2472 return ipmi::response(ccParameterNotSupported);
2473 }
2474 }
2475}
2476
Zhu, Yungebe560b02019-04-21 21:19:21 -04002477ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2478 uint8_t faultState,
2479 uint8_t faultGroup,
2480 std::array<uint8_t, 8>& ledStateData)
2481{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002482 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2483 static const std::array<std::string, maxFaultType> faultNames = {
2484 "faultFan", "faultTemp", "faultPower",
2485 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002486
2487 constexpr uint8_t maxFaultSource = 0x4;
2488 constexpr uint8_t skipLEDs = 0xFF;
2489 constexpr uint8_t pinSize = 64;
2490 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002491 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002492
Zhikui Rence4e73f2019-12-06 13:59:47 -08002493 // same pin names need to be defined in dts file
2494 static const std::array<std::array<std::string, groupSize>, groupNum>
2495 faultLedPinNames = {{
2496 "LED_CPU1_CH1_DIMM1_FAULT",
2497 "LED_CPU1_CH1_DIMM2_FAULT",
2498 "LED_CPU1_CH2_DIMM1_FAULT",
2499 "LED_CPU1_CH2_DIMM2_FAULT",
2500 "LED_CPU1_CH3_DIMM1_FAULT",
2501 "LED_CPU1_CH3_DIMM2_FAULT",
2502 "LED_CPU1_CH4_DIMM1_FAULT",
2503 "LED_CPU1_CH4_DIMM2_FAULT",
2504 "LED_CPU1_CH5_DIMM1_FAULT",
2505 "LED_CPU1_CH5_DIMM2_FAULT",
2506 "LED_CPU1_CH6_DIMM1_FAULT",
2507 "LED_CPU1_CH6_DIMM2_FAULT",
2508 "",
2509 "",
2510 "",
2511 "", // end of group1
2512 "LED_CPU2_CH1_DIMM1_FAULT",
2513 "LED_CPU2_CH1_DIMM2_FAULT",
2514 "LED_CPU2_CH2_DIMM1_FAULT",
2515 "LED_CPU2_CH2_DIMM2_FAULT",
2516 "LED_CPU2_CH3_DIMM1_FAULT",
2517 "LED_CPU2_CH3_DIMM2_FAULT",
2518 "LED_CPU2_CH4_DIMM1_FAULT",
2519 "LED_CPU2_CH4_DIMM2_FAULT",
2520 "LED_CPU2_CH5_DIMM1_FAULT",
2521 "LED_CPU2_CH5_DIMM2_FAULT",
2522 "LED_CPU2_CH6_DIMM1_FAULT",
2523 "LED_CPU2_CH6_DIMM2_FAULT",
2524 "",
2525 "",
2526 "",
2527 "", // endof group2
2528 "LED_CPU3_CH1_DIMM1_FAULT",
2529 "LED_CPU3_CH1_DIMM2_FAULT",
2530 "LED_CPU3_CH2_DIMM1_FAULT",
2531 "LED_CPU3_CH2_DIMM2_FAULT",
2532 "LED_CPU3_CH3_DIMM1_FAULT",
2533 "LED_CPU3_CH3_DIMM2_FAULT",
2534 "LED_CPU3_CH4_DIMM1_FAULT",
2535 "LED_CPU3_CH4_DIMM2_FAULT",
2536 "LED_CPU3_CH5_DIMM1_FAULT",
2537 "LED_CPU3_CH5_DIMM2_FAULT",
2538 "LED_CPU3_CH6_DIMM1_FAULT",
2539 "LED_CPU3_CH6_DIMM2_FAULT",
2540 "",
2541 "",
2542 "",
2543 "", // end of group3
2544 "LED_CPU4_CH1_DIMM1_FAULT",
2545 "LED_CPU4_CH1_DIMM2_FAULT",
2546 "LED_CPU4_CH2_DIMM1_FAULT",
2547 "LED_CPU4_CH2_DIMM2_FAULT",
2548 "LED_CPU4_CH3_DIMM1_FAULT",
2549 "LED_CPU4_CH3_DIMM2_FAULT",
2550 "LED_CPU4_CH4_DIMM1_FAULT",
2551 "LED_CPU4_CH4_DIMM2_FAULT",
2552 "LED_CPU4_CH5_DIMM1_FAULT",
2553 "LED_CPU4_CH5_DIMM2_FAULT",
2554 "LED_CPU4_CH6_DIMM1_FAULT",
2555 "LED_CPU4_CH6_DIMM2_FAULT",
2556 "",
2557 "",
2558 "",
2559 "", // end of group4
2560 "LED_FAN1_FAULT",
2561 "LED_FAN2_FAULT",
2562 "LED_FAN3_FAULT",
2563 "LED_FAN4_FAULT",
2564 "LED_FAN5_FAULT",
2565 "LED_FAN6_FAULT",
2566 "LED_FAN7_FAULT",
2567 "LED_FAN8_FAULT",
2568 "",
2569 "",
2570 "",
2571 "",
2572 "",
2573 "",
2574 "",
2575 "" // end of group5
2576 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002577
Zhikui Rence4e73f2019-12-06 13:59:47 -08002578 // Validate the source, fault type --
2579 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2580 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2581 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2582 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2583 // definition differs based on fault type (Byte 2)
2584 // Type Fan=> Group: 0=FanGroupID, FF-not used
2585 // Byte 5-11 00h, not used
2586 // Byte12 FanLedState [7:0]-Fans 7:0
2587 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2588 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2589 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2590 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2591 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2592 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2593 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2594 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002595 if ((sourceId >= maxFaultSource) ||
2596 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2597 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2598 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2599 {
2600 return ipmi::responseParmOutOfRange();
2601 }
2602
Zhikui Rence4e73f2019-12-06 13:59:47 -08002603 size_t pinGroupOffset = 0;
2604 size_t pinGroupMax = pinSize / groupSize;
2605 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002606 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002607 pinGroupOffset = 4;
2608 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002609 }
2610
2611 switch (RemoteFaultType(faultType))
2612 {
2613 case (RemoteFaultType::fan):
2614 case (RemoteFaultType::memory):
2615 {
2616 if (faultGroup == skipLEDs)
2617 {
2618 return ipmi::responseSuccess();
2619 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002620 // calculate led state bit filed count, each byte has 8bits
2621 // the maximum bits will be 8 * 8 bits
2622 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002623
2624 // assemble ledState
2625 uint64_t ledState = 0;
2626 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002627 for (int i = 0; i < sizeof(ledStateData); i++)
2628 {
2629 ledState = (uint64_t)(ledState << 8);
2630 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2631 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002632 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002633
Zhikui Rence4e73f2019-12-06 13:59:47 -08002634 for (int group = 0; group < pinGroupMax; group++)
2635 {
2636 for (int i = 0; i < groupSize; i++)
2637 { // skip non-existing pins
2638 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2639 {
2640 continue;
2641 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002642
Zhikui Rence4e73f2019-12-06 13:59:47 -08002643 gpiod::line line = gpiod::find_line(
2644 faultLedPinNames[group + pinGroupOffset][i]);
2645 if (!line)
2646 {
2647 phosphor::logging::log<phosphor::logging::level::ERR>(
2648 "Not Find Led Gpio Device!",
2649 phosphor::logging::entry(
2650 "DEVICE=%s",
2651 faultLedPinNames[group + pinGroupOffset][i]
2652 .c_str()));
2653 hasError = true;
2654 continue;
2655 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002656
Zhikui Rence4e73f2019-12-06 13:59:47 -08002657 bool activeHigh =
2658 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2659 try
2660 {
2661 line.request(
2662 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2663 activeHigh
2664 ? 0
2665 : gpiod::line_request::FLAG_ACTIVE_LOW});
2666 line.set_value(ledStateBits[i + group * groupSize]);
2667 }
2668 catch (std::system_error&)
2669 {
2670 phosphor::logging::log<phosphor::logging::level::ERR>(
2671 "Error write Led Gpio Device!",
2672 phosphor::logging::entry(
2673 "DEVICE=%s",
2674 faultLedPinNames[group + pinGroupOffset][i]
2675 .c_str()));
2676 hasError = true;
2677 continue;
2678 }
2679 } // for int i
2680 }
2681 if (hasError)
2682 {
2683 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002684 }
2685 break;
2686 }
2687 default:
2688 {
2689 // now only support two fault types
2690 return ipmi::responseParmOutOfRange();
2691 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002692 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002693 return ipmi::responseSuccess();
2694}
2695
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302696ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2697{
2698 uint8_t prodId = 0;
2699 try
2700 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002701 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302702 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002703 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302704 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2705 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002706 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302707 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2708 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302709 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2710 }
2711 catch (std::exception& e)
2712 {
2713 phosphor::logging::log<phosphor::logging::level::ERR>(
2714 "ipmiOEMReadBoardProductId: Product ID read failed!",
2715 phosphor::logging::entry("ERR=%s", e.what()));
2716 }
2717 return ipmi::responseSuccess(prodId);
2718}
2719
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302720/** @brief implements the get security mode command
2721 * @param ctx - ctx pointer
2722 *
2723 * @returns IPMI completion code with following data
2724 * - restriction mode value - As specified in
2725 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2726 * - special mode value - As specified in
2727 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2728 */
2729ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2730{
2731 namespace securityNameSpace =
2732 sdbusplus::xyz::openbmc_project::Control::Security::server;
2733 uint8_t restrictionModeValue = 0;
2734 uint8_t specialModeValue = 0;
2735
2736 boost::system::error_code ec;
2737 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002738 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302739 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2740 restricionModeProperty);
2741 if (ec)
2742 {
2743 phosphor::logging::log<phosphor::logging::level::ERR>(
2744 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2745 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2746 return ipmi::responseUnspecifiedError();
2747 }
2748 restrictionModeValue = static_cast<uint8_t>(
2749 securityNameSpace::RestrictionMode::convertModesFromString(
2750 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302751 auto varSpecialMode =
2752 ctx->bus->yield_method_call<std::variant<std::string>>(
2753 ctx->yield, ec, specialModeService, specialModeBasePath,
2754 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2755 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302756 if (ec)
2757 {
2758 phosphor::logging::log<phosphor::logging::level::ERR>(
2759 "ipmiGetSecurityMode: failed to get SpecialMode property",
2760 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2761 // fall through, let us not worry about SpecialMode property, which is
2762 // not required in user scenario
2763 }
2764 else
2765 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302766 specialModeValue = static_cast<uint8_t>(
2767 securityNameSpace::SpecialMode::convertModesFromString(
2768 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302769 }
2770 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2771}
2772
2773/** @brief implements the set security mode command
2774 * Command allows to upgrade the restriction mode and won't allow
2775 * to downgrade from system interface
2776 * @param ctx - ctx pointer
2777 * @param restrictionMode - restriction mode value to be set.
2778 *
2779 * @returns IPMI completion code
2780 */
2781ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302782 uint8_t restrictionMode,
2783 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302784{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302785#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2786 if (specialMode)
2787 {
2788 return ipmi::responseReqDataLenInvalid();
2789 }
2790#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302791 namespace securityNameSpace =
2792 sdbusplus::xyz::openbmc_project::Control::Security::server;
2793
2794 ChannelInfo chInfo;
2795 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2796 {
2797 phosphor::logging::log<phosphor::logging::level::ERR>(
2798 "ipmiSetSecurityMode: Failed to get Channel Info",
2799 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2800 return ipmi::responseUnspecifiedError();
2801 }
2802 auto reqMode =
2803 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2804
2805 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2806 (reqMode >
2807 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2808 {
2809 return ipmi::responseInvalidFieldRequest();
2810 }
2811
2812 boost::system::error_code ec;
2813 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002814 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302815 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2816 restricionModeProperty);
2817 if (ec)
2818 {
2819 phosphor::logging::log<phosphor::logging::level::ERR>(
2820 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2821 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2822 return ipmi::responseUnspecifiedError();
2823 }
2824 auto currentRestrictionMode =
2825 securityNameSpace::RestrictionMode::convertModesFromString(
2826 std::get<std::string>(varRestrMode));
2827
2828 if (chInfo.mediumType !=
2829 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2830 currentRestrictionMode > reqMode)
2831 {
2832 phosphor::logging::log<phosphor::logging::level::ERR>(
2833 "ipmiSetSecurityMode - Downgrading security mode not supported "
2834 "through system interface",
2835 phosphor::logging::entry(
2836 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2837 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2838 return ipmi::responseCommandNotAvailable();
2839 }
2840
2841 ec.clear();
2842 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002843 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302844 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2845 restricionModeProperty,
2846 static_cast<std::variant<std::string>>(
2847 securityNameSpace::convertForMessage(reqMode)));
2848
2849 if (ec)
2850 {
2851 phosphor::logging::log<phosphor::logging::level::ERR>(
2852 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2853 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2854 return ipmi::responseUnspecifiedError();
2855 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302856
2857#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2858 if (specialMode)
2859 {
2860 ec.clear();
2861 ctx->bus->yield_method_call<>(
2862 ctx->yield, ec, specialModeService, specialModeBasePath,
2863 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2864 specialModeProperty,
2865 static_cast<std::variant<std::string>>(
2866 securityNameSpace::convertForMessage(
2867 static_cast<securityNameSpace::SpecialMode::Modes>(
2868 specialMode.value()))));
2869
2870 if (ec)
2871 {
2872 phosphor::logging::log<phosphor::logging::level::ERR>(
2873 "ipmiSetSecurityMode: failed to set SpecialMode property",
2874 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2875 return ipmi::responseUnspecifiedError();
2876 }
2877 }
2878#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302879 return ipmi::responseSuccess();
2880}
2881
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002882ipmi::RspType<uint8_t /* restore status */>
2883 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2884{
2885 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2886
2887 if (clr != expClr)
2888 {
2889 return ipmi::responseInvalidFieldRequest();
2890 }
2891 constexpr uint8_t cmdStatus = 0;
2892 constexpr uint8_t cmdDefaultRestore = 0xaa;
2893 constexpr uint8_t cmdFullRestore = 0xbb;
2894 constexpr uint8_t cmdFormat = 0xcc;
2895
2896 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2897
2898 switch (cmd)
2899 {
2900 case cmdStatus:
2901 break;
2902 case cmdDefaultRestore:
2903 case cmdFullRestore:
2904 case cmdFormat:
2905 {
2906 // write file to rwfs root
2907 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2908 std::ofstream restoreFile(restoreOpFname);
2909 if (!restoreFile)
2910 {
2911 return ipmi::responseUnspecifiedError();
2912 }
2913 restoreFile << value << "\n";
2914 break;
2915 }
2916 default:
2917 return ipmi::responseInvalidFieldRequest();
2918 }
2919
2920 constexpr uint8_t restorePending = 0;
2921 constexpr uint8_t restoreComplete = 1;
2922
2923 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2924 ? restorePending
2925 : restoreComplete;
2926 return ipmi::responseSuccess(restoreStatus);
2927}
2928
Chen Yugang39736d52019-07-12 16:24:33 +08002929ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2930{
2931 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002932 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002933
2934 try
2935 {
2936 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2937 std::string service =
2938 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2939 Value variant =
2940 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2941 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2942
2943 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2944 std::get<std::string>(variant)))
2945 {
2946 case nmi::NMISource::BMCSourceSignal::None:
2947 bmcSource = static_cast<uint8_t>(NmiSource::none);
2948 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002949 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2950 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002951 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002952 case nmi::NMISource::BMCSourceSignal::Watchdog:
2953 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002954 break;
2955 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2956 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2957 break;
2958 case nmi::NMISource::BMCSourceSignal::MemoryError:
2959 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2960 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002961 case nmi::NMISource::BMCSourceSignal::PciBusError:
2962 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002963 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002964 case nmi::NMISource::BMCSourceSignal::PCH:
2965 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002966 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002967 case nmi::NMISource::BMCSourceSignal::Chipset:
2968 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002969 break;
2970 default:
2971 phosphor::logging::log<phosphor::logging::level::ERR>(
2972 "NMI source: invalid property!",
2973 phosphor::logging::entry(
2974 "PROP=%s", std::get<std::string>(variant).c_str()));
2975 return ipmi::responseResponseError();
2976 }
2977 }
2978 catch (sdbusplus::exception::SdBusError& e)
2979 {
2980 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2981 return ipmi::responseResponseError();
2982 }
2983
2984 return ipmi::responseSuccess(bmcSource);
2985}
2986
2987ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2988{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002989 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002990
2991 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2992 nmi::NMISource::BMCSourceSignal::None;
2993
2994 switch (NmiSource(sourceId))
2995 {
2996 case NmiSource::none:
2997 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2998 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002999 case NmiSource::frontPanelButton:
3000 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08003001 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003002 case NmiSource::watchdog:
3003 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08003004 break;
3005 case NmiSource::chassisCmd:
3006 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
3007 break;
3008 case NmiSource::memoryError:
3009 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
3010 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003011 case NmiSource::pciBusError:
3012 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08003013 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003014 case NmiSource::pch:
3015 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003016 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003017 case NmiSource::chipset:
3018 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003019 break;
3020 default:
3021 phosphor::logging::log<phosphor::logging::level::ERR>(
3022 "NMI source: invalid property!");
3023 return ipmi::responseResponseError();
3024 }
3025
3026 try
3027 {
3028 // keep NMI signal source
3029 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3030 std::string service =
3031 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003032 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3033 oemNmiBmcSourceObjPathProp,
3034 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003035 // set Enabled property to inform NMI source handling
3036 // to trigger a NMI_OUT BSOD.
3037 // if it's triggered by NMI source property changed,
3038 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3039 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3040 {
3041 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3042 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3043 static_cast<bool>(true));
3044 }
Chen Yugang39736d52019-07-12 16:24:33 +08003045 }
3046 catch (sdbusplus::exception_t& e)
3047 {
3048 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3049 return ipmi::responseResponseError();
3050 }
3051
3052 return ipmi::responseSuccess();
3053}
3054
James Feist63efafa2019-07-24 12:39:21 -07003055namespace dimmOffset
3056{
3057constexpr const char* dimmPower = "DimmPower";
3058constexpr const char* staticCltt = "StaticCltt";
3059constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3060constexpr const char* offsetInterface =
3061 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3062constexpr const char* property = "DimmOffset";
3063
3064}; // namespace dimmOffset
3065
3066ipmi::RspType<>
3067 ipmiOEMSetDimmOffset(uint8_t type,
3068 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3069{
3070 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3071 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3072 {
3073 return ipmi::responseInvalidFieldRequest();
3074 }
3075
3076 if (data.empty())
3077 {
3078 return ipmi::responseInvalidFieldRequest();
3079 }
3080 nlohmann::json json;
3081
3082 std::ifstream jsonStream(dimmOffsetFile);
3083 if (jsonStream.good())
3084 {
3085 json = nlohmann::json::parse(jsonStream, nullptr, false);
3086 if (json.is_discarded())
3087 {
3088 json = nlohmann::json();
3089 }
3090 jsonStream.close();
3091 }
3092
3093 std::string typeName;
3094 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3095 {
3096 typeName = dimmOffset::dimmPower;
3097 }
3098 else
3099 {
3100 typeName = dimmOffset::staticCltt;
3101 }
3102
3103 nlohmann::json& field = json[typeName];
3104
3105 for (const auto& [index, value] : data)
3106 {
3107 field[index] = value;
3108 }
3109
3110 for (nlohmann::json& val : field)
3111 {
3112 if (val == nullptr)
3113 {
3114 val = static_cast<uint8_t>(0);
3115 }
3116 }
3117
3118 std::ofstream output(dimmOffsetFile);
3119 if (!output.good())
3120 {
3121 std::cerr << "Error writing json file\n";
3122 return ipmi::responseResponseError();
3123 }
3124
3125 output << json.dump(4);
3126
3127 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3128 {
3129 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3130
3131 std::variant<std::vector<uint8_t>> offsets =
3132 field.get<std::vector<uint8_t>>();
3133 auto call = bus->new_method_call(
3134 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3135 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3136 try
3137 {
3138 bus->call(call);
3139 }
3140 catch (sdbusplus::exception_t& e)
3141 {
3142 phosphor::logging::log<phosphor::logging::level::ERR>(
3143 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3144 phosphor::logging::entry("ERR=%s", e.what()));
3145 return ipmi::responseResponseError();
3146 }
3147 }
3148
3149 return ipmi::responseSuccess();
3150}
3151
3152ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3153{
3154
3155 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3156 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3157 {
3158 return ipmi::responseInvalidFieldRequest();
3159 }
3160
3161 std::ifstream jsonStream(dimmOffsetFile);
3162
3163 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3164 if (json.is_discarded())
3165 {
3166 std::cerr << "File error in " << dimmOffsetFile << "\n";
3167 return ipmi::responseResponseError();
3168 }
3169
3170 std::string typeName;
3171 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3172 {
3173 typeName = dimmOffset::dimmPower;
3174 }
3175 else
3176 {
3177 typeName = dimmOffset::staticCltt;
3178 }
3179
3180 auto it = json.find(typeName);
3181 if (it == json.end())
3182 {
3183 return ipmi::responseInvalidFieldRequest();
3184 }
3185
3186 if (it->size() <= index)
3187 {
3188 return ipmi::responseInvalidFieldRequest();
3189 }
3190
3191 uint8_t resp = it->at(index).get<uint8_t>();
3192 return ipmi::responseSuccess(resp);
3193}
3194
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003195namespace boot_options
3196{
3197
3198using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3199using IpmiValue = uint8_t;
3200constexpr auto ipmiDefault = 0;
3201
3202std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3203 {0x01, Source::Sources::Network},
3204 {0x02, Source::Sources::Disk},
3205 {0x05, Source::Sources::ExternalMedia},
3206 {0x0f, Source::Sources::RemovableMedia},
3207 {ipmiDefault, Source::Sources::Default}};
3208
3209std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003210 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003211
3212std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3213 {Source::Sources::Network, 0x01},
3214 {Source::Sources::Disk, 0x02},
3215 {Source::Sources::ExternalMedia, 0x05},
3216 {Source::Sources::RemovableMedia, 0x0f},
3217 {Source::Sources::Default, ipmiDefault}};
3218
3219std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003220 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003221
3222static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3223static constexpr auto bootSourceIntf =
3224 "xyz.openbmc_project.Control.Boot.Source";
3225static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3226static constexpr auto persistentObjPath =
3227 "/xyz/openbmc_project/control/host0/boot";
3228static constexpr auto oneTimePath =
3229 "/xyz/openbmc_project/control/host0/boot/one_time";
3230static constexpr auto bootSourceProp = "BootSource";
3231static constexpr auto bootModeProp = "BootMode";
3232static constexpr auto oneTimeBootEnableProp = "Enabled";
3233static constexpr auto httpBootMode =
3234 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3235
3236enum class BootOptionParameter : size_t
3237{
3238 setInProgress = 0x0,
3239 bootFlags = 0x5,
3240};
3241static constexpr uint8_t setComplete = 0x0;
3242static constexpr uint8_t setInProgress = 0x1;
3243static uint8_t transferStatus = setComplete;
3244static constexpr uint8_t setParmVersion = 0x01;
3245static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3246static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3247static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3248static constexpr uint8_t httpBoot = 0xd;
3249static constexpr uint8_t bootSourceMask = 0x3c;
3250
3251} // namespace boot_options
3252
3253ipmi::RspType<uint8_t, // version
3254 uint8_t, // param
3255 uint8_t, // data0, dependent on parameter
3256 std::optional<uint8_t> // data1, dependent on parameter
3257 >
3258 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3259{
3260 using namespace boot_options;
3261 uint8_t bootOption = 0;
3262
3263 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3264 {
3265 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3266 std::nullopt);
3267 }
3268
3269 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3270 {
3271 phosphor::logging::log<phosphor::logging::level::ERR>(
3272 "Unsupported parameter");
3273 return ipmi::responseResponseError();
3274 }
3275
3276 try
3277 {
3278 auto oneTimeEnabled = false;
3279 // read one time Enabled property
3280 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3281 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3282 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3283 enabledIntf, oneTimeBootEnableProp);
3284 oneTimeEnabled = std::get<bool>(variant);
3285
3286 // get BootSource and BootMode properties
3287 // according to oneTimeEnable
3288 auto bootObjPath = oneTimePath;
3289 if (oneTimeEnabled == false)
3290 {
3291 bootObjPath = persistentObjPath;
3292 }
3293
3294 service = getService(*dbus, bootModeIntf, bootObjPath);
3295 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3296 bootModeProp);
3297
3298 auto bootMode =
3299 Mode::convertModesFromString(std::get<std::string>(variant));
3300
3301 service = getService(*dbus, bootSourceIntf, bootObjPath);
3302 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3303 bootSourceProp);
3304
3305 if (std::get<std::string>(variant) == httpBootMode)
3306 {
3307 bootOption = httpBoot;
3308 }
3309 else
3310 {
3311 auto bootSource = Source::convertSourcesFromString(
3312 std::get<std::string>(variant));
3313 bootOption = sourceDbusToIpmi.at(bootSource);
3314 if (Source::Sources::Default == bootSource)
3315 {
3316 bootOption = modeDbusToIpmi.at(bootMode);
3317 }
3318 }
3319
3320 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3321 : setParmBootFlagsValidPermanent;
3322 bootOption <<= 2; // shift for responseconstexpr
3323 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3324 bootOption);
3325 }
3326 catch (sdbusplus::exception_t& e)
3327 {
3328 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3329 return ipmi::responseResponseError();
3330 }
3331}
3332
3333ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3334 std::optional<uint8_t> bootOption)
3335{
3336 using namespace boot_options;
3337 auto oneTimeEnabled = false;
3338
3339 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3340 {
3341 if (bootOption)
3342 {
3343 return ipmi::responseReqDataLenInvalid();
3344 }
3345
3346 if (transferStatus == setInProgress)
3347 {
3348 phosphor::logging::log<phosphor::logging::level::ERR>(
3349 "boot option set in progress!");
3350 return ipmi::responseResponseError();
3351 }
3352
3353 transferStatus = bootParam;
3354 return ipmi::responseSuccess();
3355 }
3356
3357 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3358 {
3359 phosphor::logging::log<phosphor::logging::level::ERR>(
3360 "Unsupported parameter");
3361 return ipmi::responseResponseError();
3362 }
3363
3364 if (!bootOption)
3365 {
3366 return ipmi::responseReqDataLenInvalid();
3367 }
3368
3369 if (((bootOption.value() & bootSourceMask) >> 2) !=
3370 httpBoot) // not http boot, exit
3371 {
3372 phosphor::logging::log<phosphor::logging::level::ERR>(
3373 "wrong boot option parameter!");
3374 return ipmi::responseParmOutOfRange();
3375 }
3376
3377 try
3378 {
3379 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3380 setParmBootFlagsPermanent;
3381
3382 // read one time Enabled property
3383 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3384 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3385 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3386 enabledIntf, oneTimeBootEnableProp);
3387 oneTimeEnabled = std::get<bool>(variant);
3388
3389 /*
3390 * Check if the current boot setting is onetime or permanent, if the
3391 * request in the command is otherwise, then set the "Enabled"
3392 * property in one_time object path to 'True' to indicate onetime
3393 * and 'False' to indicate permanent.
3394 *
3395 * Once the onetime/permanent setting is applied, then the bootMode
3396 * and bootSource is updated for the corresponding object.
3397 */
3398 if (permanent == oneTimeEnabled)
3399 {
3400 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3401 oneTimeBootEnableProp, !permanent);
3402 }
3403
3404 // set BootSource and BootMode properties
3405 // according to oneTimeEnable or persistent
3406 auto bootObjPath = oneTimePath;
3407 if (oneTimeEnabled == false)
3408 {
3409 bootObjPath = persistentObjPath;
3410 }
3411 std::string bootMode =
3412 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3413 std::string bootSource = httpBootMode;
3414
3415 service = getService(*dbus, bootModeIntf, bootObjPath);
3416 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3417 bootMode);
3418
3419 service = getService(*dbus, bootSourceIntf, bootObjPath);
3420 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3421 bootSourceProp, bootSource);
3422 }
3423 catch (sdbusplus::exception_t& e)
3424 {
3425 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3426 return ipmi::responseResponseError();
3427 }
3428
3429 return ipmi::responseSuccess();
3430}
3431
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003432using BasicVariantType =
3433 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3434 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3435 uint16_t, uint8_t, bool>;
3436using PropertyMapType =
3437 boost::container::flat_map<std::string, BasicVariantType>;
3438static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3439 "xyz.openbmc_project.Configuration.PSUPresence"};
3440int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3441 std::vector<uint64_t>& addrTable)
3442{
3443 boost::system::error_code ec;
3444 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3445 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3446 "/xyz/openbmc_project/object_mapper",
3447 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3448 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3449 if (ec)
3450 {
3451 phosphor::logging::log<phosphor::logging::level::ERR>(
3452 "Failed to set dbus property to cold redundancy");
3453 return -1;
3454 }
3455 for (const auto& object : subtree)
3456 {
3457 std::string pathName = object.first;
3458 for (const auto& serviceIface : object.second)
3459 {
3460 std::string serviceName = serviceIface.first;
3461
3462 ec.clear();
3463 PropertyMapType propMap =
3464 ctx->bus->yield_method_call<PropertyMapType>(
3465 ctx->yield, ec, serviceName, pathName,
3466 "org.freedesktop.DBus.Properties", "GetAll",
3467 "xyz.openbmc_project.Configuration.PSUPresence");
3468 if (ec)
3469 {
3470 phosphor::logging::log<phosphor::logging::level::ERR>(
3471 "Failed to set dbus property to cold redundancy");
3472 return -1;
3473 }
3474 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3475 auto psuAddress =
3476 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3477
3478 if (psuBus == nullptr || psuAddress == nullptr)
3479 {
3480 std::cerr << "error finding necessary "
3481 "entry in configuration\n";
3482 return -1;
3483 }
3484 bus = static_cast<uint8_t>(*psuBus);
3485 addrTable = *psuAddress;
3486 return 0;
3487 }
3488 }
3489 return -1;
3490}
3491
3492static const constexpr uint8_t addrOffset = 8;
3493static const constexpr uint8_t psuRevision = 0xd9;
3494static const constexpr uint8_t defaultPSUBus = 7;
3495// Second Minor, Primary Minor, Major
3496static const constexpr size_t verLen = 3;
3497ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3498{
3499 uint8_t bus = defaultPSUBus;
3500 std::vector<uint64_t> addrTable;
3501 std::vector<uint8_t> result;
3502 if (getPSUAddress(ctx, bus, addrTable))
3503 {
3504 std::cerr << "Failed to get PSU bus and address\n";
3505 return ipmi::responseResponseError();
3506 }
3507
3508 for (const auto& slaveAddr : addrTable)
3509 {
3510 std::vector<uint8_t> writeData = {psuRevision};
3511 std::vector<uint8_t> readBuf(verLen);
3512 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3513 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3514
3515 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3516 if (retI2C != ipmi::ccSuccess)
3517 {
3518 for (size_t idx = 0; idx < verLen; idx++)
3519 {
3520 result.emplace_back(0x00);
3521 }
3522 }
3523 else
3524 {
3525 for (const uint8_t& data : readBuf)
3526 {
3527 result.emplace_back(data);
3528 }
3529 }
3530 }
3531
3532 return ipmi::responseSuccess(result);
3533}
3534
AppaRao Puli28972062019-11-11 02:04:45 +05303535/** @brief implements the maximum size of
3536 * bridgeable messages used between KCS and
3537 * IPMB interfacesget security mode command.
3538 *
3539 * @returns IPMI completion code with following data
3540 * - KCS Buffer Size (In multiples of four bytes)
3541 * - IPMB Buffer Size (In multiples of four bytes)
3542 **/
3543ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3544{
3545 // for now this is hard coded; really this number is dependent on
3546 // the BMC kcs driver as well as the host kcs driver....
3547 // we can't know the latter.
3548 uint8_t kcsMaxBufferSize = 63 / 4;
3549 uint8_t ipmbMaxBufferSize = 128 / 4;
3550
3551 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3552}
3553
Jason M. Bills64796042018-10-03 16:51:55 -07003554static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003555{
3556 phosphor::logging::log<phosphor::logging::level::INFO>(
3557 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003558 ipmiPrintAndRegister(intel::netFnGeneral,
3559 intel::general::cmdGetChassisIdentifier, NULL,
3560 ipmiOEMGetChassisIdentifier,
3561 PRIVILEGE_USER); // get chassis identifier
3562
3563 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3564 NULL, ipmiOEMSetSystemGUID,
3565 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003566
3567 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003568 registerHandler(prioOemBase, intel::netFnGeneral,
3569 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3570 ipmiOEMDisableBMCSystemReset);
3571
Jason M. Billsb02bf092019-08-15 13:01:56 -07003572 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003573 registerHandler(prioOemBase, intel::netFnGeneral,
3574 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3575 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003576
Vernon Mauery98bbf692019-09-16 11:14:59 -07003577 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3578 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003579
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003580 registerHandler(prioOemBase, intel::netFnGeneral,
3581 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3582 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003583
Vernon Mauery98bbf692019-09-16 11:14:59 -07003584 ipmiPrintAndRegister(intel::netFnGeneral,
3585 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3586 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303587
Vernon Mauery98bbf692019-09-16 11:14:59 -07003588 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3589 intel::general::cmdSendEmbeddedFWUpdStatus,
3590 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303591
Rajashekar Gade Reddy2b664d52020-03-23 22:09:00 +05303592 registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb,
3593 Privilege::Admin, ipmiOEMSlotIpmb);
3594
Vernon Mauery98bbf692019-09-16 11:14:59 -07003595 ipmiPrintAndRegister(intel::netFnGeneral,
3596 intel::general::cmdSetPowerRestoreDelay, NULL,
3597 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3598
3599 ipmiPrintAndRegister(intel::netFnGeneral,
3600 intel::general::cmdGetPowerRestoreDelay, NULL,
3601 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3602
3603 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3604 intel::general::cmdSetOEMUser2Activation,
3605 Privilege::Callback, ipmiOEMSetUser2Activation);
3606
3607 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3608 intel::general::cmdSetSpecialUserPassword,
3609 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303610
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003611 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003612 registerHandler(prioOemBase, intel::netFnGeneral,
3613 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3614 ipmiOEMGetProcessorErrConfig);
3615
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003616 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003617 registerHandler(prioOemBase, intel::netFnGeneral,
3618 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3619 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003620
Vernon Mauery98bbf692019-09-16 11:14:59 -07003621 ipmiPrintAndRegister(intel::netFnGeneral,
3622 intel::general::cmdSetShutdownPolicy, NULL,
3623 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003624
Vernon Mauery98bbf692019-09-16 11:14:59 -07003625 ipmiPrintAndRegister(intel::netFnGeneral,
3626 intel::general::cmdGetShutdownPolicy, NULL,
3627 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003628
anil kumar appanaf945eee2019-09-25 23:29:11 +00003629 registerHandler(prioOemBase, intel::netFnGeneral,
3630 intel::general::cmdSetFanConfig, Privilege::User,
3631 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003632
Vernon Mauery98bbf692019-09-16 11:14:59 -07003633 registerHandler(prioOemBase, intel::netFnGeneral,
3634 intel::general::cmdGetFanConfig, Privilege::User,
3635 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003636
Vernon Mauery98bbf692019-09-16 11:14:59 -07003637 registerHandler(prioOemBase, intel::netFnGeneral,
3638 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3639 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003640
Vernon Mauery98bbf692019-09-16 11:14:59 -07003641 registerHandler(prioOemBase, intel::netFnGeneral,
3642 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3643 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003644
Vernon Mauery98bbf692019-09-16 11:14:59 -07003645 registerHandler(prioOemBase, intel::netFnGeneral,
3646 intel::general::cmdSetFscParameter, Privilege::User,
3647 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003648
Vernon Mauery98bbf692019-09-16 11:14:59 -07003649 registerHandler(prioOemBase, intel::netFnGeneral,
3650 intel::general::cmdGetFscParameter, Privilege::User,
3651 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303652
Vernon Mauery98bbf692019-09-16 11:14:59 -07003653 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3654 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3655 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003656
Vernon Mauery98bbf692019-09-16 11:14:59 -07003657 registerHandler(prioOemBase, intel::netFnGeneral,
3658 intel::general::cmdGetNmiStatus, Privilege::User,
3659 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003660
Vernon Mauery98bbf692019-09-16 11:14:59 -07003661 registerHandler(prioOemBase, intel::netFnGeneral,
3662 intel::general::cmdSetNmiStatus, Privilege::Operator,
3663 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003664
Vernon Mauery98bbf692019-09-16 11:14:59 -07003665 registerHandler(prioOemBase, intel::netFnGeneral,
3666 intel::general::cmdGetEfiBootOptions, Privilege::User,
3667 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003668
Vernon Mauery98bbf692019-09-16 11:14:59 -07003669 registerHandler(prioOemBase, intel::netFnGeneral,
3670 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3671 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303672
Vernon Mauery98bbf692019-09-16 11:14:59 -07003673 registerHandler(prioOemBase, intel::netFnGeneral,
3674 intel::general::cmdGetSecurityMode, Privilege::User,
3675 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303676
Vernon Mauery98bbf692019-09-16 11:14:59 -07003677 registerHandler(prioOemBase, intel::netFnGeneral,
3678 intel::general::cmdSetSecurityMode, Privilege::Admin,
3679 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003680
NITIN SHARMAabd11ca2019-06-12 12:31:42 +00003681 registerHandler(prioOemBase, intel::netFnGeneral,
3682 intel::general::cmdGetLEDStatus, Privilege::Admin,
3683 ipmiOEMGetLEDStatus);
Cheng C Yang773703a2019-08-15 09:41:11 +08003684
Vernon Mauery98bbf692019-09-16 11:14:59 -07003685 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3686 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3687 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3688
3689 registerHandler(prioOemBase, intel::netFnGeneral,
3690 intel::general::cmdSetFaultIndication, Privilege::Operator,
3691 ipmiOEMSetFaultIndication);
3692
3693 registerHandler(prioOemBase, intel::netFnGeneral,
3694 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3695 ipmiOEMSetCRConfig);
3696
3697 registerHandler(prioOemBase, intel::netFnGeneral,
3698 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3699 ipmiOEMGetCRConfig);
3700
3701 registerHandler(prioOemBase, intel::netFnGeneral,
3702 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003703 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003704
Vernon Mauery98bbf692019-09-16 11:14:59 -07003705 registerHandler(prioOemBase, intel::netFnGeneral,
3706 intel::general::cmdSetDimmOffset, Privilege::Operator,
3707 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003708
Vernon Mauery98bbf692019-09-16 11:14:59 -07003709 registerHandler(prioOemBase, intel::netFnGeneral,
3710 intel::general::cmdGetDimmOffset, Privilege::Operator,
3711 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003712
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003713 registerHandler(prioOemBase, intel::netFnGeneral,
3714 intel::general::cmdGetPSUVersion, Privilege::User,
3715 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303716
3717 registerHandler(prioOemBase, intel::netFnGeneral,
3718 intel::general::cmdGetBufferSize, Privilege::User,
3719 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003720}
3721
3722} // namespace ipmi