blob: b87a2ab382cd36fc8e7dea3dd9b9ce0c55d264df [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();
Yong Li2742b852019-12-16 14:55:11 +0800288 std::string service = getService(*dbus, biosVersionIntf, biosObjPath);
289 setDbusProperty(*dbus, service, biosObjPath, biosVersionIntf,
290 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 =
366 getService(*dbus, biosVersionIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800367 try
368 {
Yong Li2742b852019-12-16 14:55:11 +0800369 Value variant =
370 getDbusProperty(*dbus, service, biosObjPath,
371 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
Jason M. Bills64796042018-10-03 16:51:55 -0700609ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
610 ipmi_request_t request,
611 ipmi_response_t response,
612 ipmi_data_len_t dataLen,
613 ipmi_context_t context)
614{
615 SetPowerRestoreDelayReq* data =
616 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
617 uint16_t delay = 0;
618
619 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
620 {
621 *dataLen = 0;
622 return IPMI_CC_REQ_DATA_LEN_INVALID;
623 }
624 delay = data->byteMSB;
625 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700626 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700627 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700628 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
629 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700630 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
631 *dataLen = 0;
632
633 return IPMI_CC_OK;
634}
635
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700636static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700637{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700638 static constexpr const char* cpuPresencePathPrefix =
639 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
640 static constexpr const char* cpuPresenceIntf =
641 "xyz.openbmc_project.Inventory.Item";
642 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
643 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
644 try
Jason M. Bills64796042018-10-03 16:51:55 -0700645 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700646 auto service =
647 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
648
649 ipmi::Value result = ipmi::getDbusProperty(
650 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
651 return std::get<bool>(result);
652 }
653 catch (const std::exception& e)
654 {
655 phosphor::logging::log<phosphor::logging::level::INFO>(
656 "Cannot find processor presence",
657 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
658 return false;
659 }
660}
661
662ipmi::RspType<bool, // CATERR Reset Enabled
663 bool, // ERR2 Reset Enabled
664 uint6_t, // reserved
665 uint8_t, // reserved, returns 0x3F
666 uint6_t, // CPU1 CATERR Count
667 uint2_t, // CPU1 Status
668 uint6_t, // CPU2 CATERR Count
669 uint2_t, // CPU2 Status
670 uint6_t, // CPU3 CATERR Count
671 uint2_t, // CPU3 Status
672 uint6_t, // CPU4 CATERR Count
673 uint2_t, // CPU4 Status
674 uint8_t // Crashdump Count
675 >
676 ipmiOEMGetProcessorErrConfig()
677{
678 bool resetOnCATERR = false;
679 bool resetOnERR2 = false;
680 uint6_t cpu1CATERRCount = 0;
681 uint6_t cpu2CATERRCount = 0;
682 uint6_t cpu3CATERRCount = 0;
683 uint6_t cpu4CATERRCount = 0;
684 uint8_t crashdumpCount = 0;
685 uint2_t cpu1Status =
686 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
687 uint2_t cpu2Status =
688 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
689 uint2_t cpu3Status =
690 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
691 uint2_t cpu4Status =
692 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
693
694 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
695 try
696 {
697 auto service = ipmi::getService(*busp, processorErrConfigIntf,
698 processorErrConfigObjPath);
699
700 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
701 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
702 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
703 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
704 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
705 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
706 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
707 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
708 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
709 }
710 catch (const std::exception& e)
711 {
712 phosphor::logging::log<phosphor::logging::level::ERR>(
713 "Failed to fetch processor error config",
714 phosphor::logging::entry("ERROR=%s", e.what()));
715 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700716 }
717
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700718 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
719 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
720 cpu2Status, cpu3CATERRCount, cpu3Status,
721 cpu4CATERRCount, cpu4Status, crashdumpCount);
722}
Jason M. Bills64796042018-10-03 16:51:55 -0700723
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700724ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
725 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
726 std::optional<bool> clearCPUErrorCount,
727 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
728{
729 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700730
731 try
732 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700733 auto service = ipmi::getService(*busp, processorErrConfigIntf,
734 processorErrConfigObjPath);
735 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
736 processorErrConfigIntf, "ResetOnCATERR",
737 resetOnCATERR);
738 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
739 processorErrConfigIntf, "ResetOnERR2",
740 resetOnERR2);
741 if (clearCPUErrorCount.value_or(false))
742 {
743 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700744 processorErrConfigIntf, "ErrorCountCPU1",
745 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700746 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700747 processorErrConfigIntf, "ErrorCountCPU2",
748 static_cast<uint8_t>(0));
749 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
750 processorErrConfigIntf, "ErrorCountCPU3",
751 static_cast<uint8_t>(0));
752 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
753 processorErrConfigIntf, "ErrorCountCPU4",
754 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700755 }
756 if (clearCrashdumpCount.value_or(false))
757 {
758 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700759 processorErrConfigIntf, "CrashdumpCount",
760 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700761 }
Jason M. Bills64796042018-10-03 16:51:55 -0700762 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700763 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700764 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800765 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700766 "Failed to set processor error config",
767 phosphor::logging::entry("EXCEPTION=%s", e.what()));
768 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700769 }
770
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700771 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700772}
773
Yong Li703922d2018-11-06 13:25:31 +0800774ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
775 ipmi_request_t request,
776 ipmi_response_t response,
777 ipmi_data_len_t dataLen,
778 ipmi_context_t context)
779{
780 GetOEMShutdownPolicyRes* resp =
781 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
782
783 if (*dataLen != 0)
784 {
785 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800786 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800787 *dataLen = 0;
788 return IPMI_CC_REQ_DATA_LEN_INVALID;
789 }
790
791 *dataLen = 0;
792
793 try
794 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700795 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800796 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700797 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
798 Value variant = getDbusProperty(
799 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
800 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800801
802 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
803 convertPolicyFromString(std::get<std::string>(variant)) ==
804 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
805 NoShutdownOnOCOT)
806 {
807 resp->policy = 0;
808 }
809 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
810 convertPolicyFromString(std::get<std::string>(variant)) ==
811 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
812 Policy::ShutdownOnOCOT)
813 {
814 resp->policy = 1;
815 }
816 else
817 {
818 phosphor::logging::log<phosphor::logging::level::ERR>(
819 "oem_set_shutdown_policy: invalid property!",
820 phosphor::logging::entry(
821 "PROP=%s", std::get<std::string>(variant).c_str()));
822 return IPMI_CC_UNSPECIFIED_ERROR;
823 }
Yong Li703922d2018-11-06 13:25:31 +0800824 // TODO needs to check if it is multi-node products,
825 // policy is only supported on node 3/4
826 resp->policySupport = shutdownPolicySupported;
827 }
828 catch (sdbusplus::exception_t& e)
829 {
830 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
831 return IPMI_CC_UNSPECIFIED_ERROR;
832 }
833
834 *dataLen = sizeof(GetOEMShutdownPolicyRes);
835 return IPMI_CC_OK;
836}
837
838ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
839 ipmi_request_t request,
840 ipmi_response_t response,
841 ipmi_data_len_t dataLen,
842 ipmi_context_t context)
843{
844 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800845 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
846 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
847 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800848
849 // TODO needs to check if it is multi-node products,
850 // policy is only supported on node 3/4
851 if (*dataLen != 1)
852 {
853 phosphor::logging::log<phosphor::logging::level::ERR>(
854 "oem_set_shutdown_policy: invalid input len!");
855 *dataLen = 0;
856 return IPMI_CC_REQ_DATA_LEN_INVALID;
857 }
858
859 *dataLen = 0;
860 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
861 {
862 phosphor::logging::log<phosphor::logging::level::ERR>(
863 "oem_set_shutdown_policy: invalid input!");
864 return IPMI_CC_INVALID_FIELD_REQUEST;
865 }
866
Yong Li0669d192019-05-06 14:01:46 +0800867 if (*req == noShutdownOnOCOT)
868 {
869 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
870 Policy::NoShutdownOnOCOT;
871 }
872 else
873 {
874 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
875 Policy::ShutdownOnOCOT;
876 }
877
Yong Li703922d2018-11-06 13:25:31 +0800878 try
879 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700880 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800881 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700882 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800883 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700884 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800885 oemShutdownPolicyObjPathProp,
886 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800887 }
888 catch (sdbusplus::exception_t& e)
889 {
890 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
891 return IPMI_CC_UNSPECIFIED_ERROR;
892 }
893
894 return IPMI_CC_OK;
895}
896
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530897/** @brief implementation for check the DHCP or not in IPv4
898 * @param[in] Channel - Channel number
899 * @returns true or false.
900 */
901static bool isDHCPEnabled(uint8_t Channel)
902{
903 try
904 {
905 auto ethdevice = getChannelName(Channel);
906 if (ethdevice.empty())
907 {
908 return false;
909 }
910 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700911 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530912 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700913 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
914 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530915 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700916 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530917 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
918 {
919 return true;
920 }
921 else
922 {
923 return false;
924 }
925 }
926 catch (sdbusplus::exception_t& e)
927 {
928 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
929 return true;
930 }
931}
932
933/** @brief implementes for check the DHCP or not in IPv6
934 * @param[in] Channel - Channel number
935 * @returns true or false.
936 */
937static bool isDHCPIPv6Enabled(uint8_t Channel)
938{
939
940 try
941 {
942 auto ethdevice = getChannelName(Channel);
943 if (ethdevice.empty())
944 {
945 return false;
946 }
947 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700948 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530949 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700950 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
951 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530952 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700953 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530954 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
955 {
956 return true;
957 }
958 else
959 {
960 return false;
961 }
962 }
963 catch (sdbusplus::exception_t& e)
964 {
965 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
966 return true;
967 }
968}
969
970/** @brief implementes the creating of default new user
971 * @param[in] userName - new username in 16 bytes.
972 * @param[in] userPassword - new password in 20 bytes
973 * @returns ipmi completion code.
974 */
975ipmi::RspType<> ipmiOEMSetUser2Activation(
976 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
977 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
978{
979 bool userState = false;
980 // Check for System Interface not exist and LAN should be static
981 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
982 {
983 ChannelInfo chInfo;
984 try
985 {
986 getChannelInfo(channel, chInfo);
987 }
988 catch (sdbusplus::exception_t& e)
989 {
990 phosphor::logging::log<phosphor::logging::level::ERR>(
991 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
992 phosphor::logging::entry("MSG: %s", e.description()));
993 return ipmi::response(ipmi::ccUnspecifiedError);
994 }
995 if (chInfo.mediumType ==
996 static_cast<uint8_t>(EChannelMediumType::systemInterface))
997 {
998 phosphor::logging::log<phosphor::logging::level::ERR>(
999 "ipmiOEMSetUser2Activation: system interface exist .");
1000 return ipmi::response(ipmi::ccCommandNotAvailable);
1001 }
1002 else
1003 {
1004
1005 if (chInfo.mediumType ==
1006 static_cast<uint8_t>(EChannelMediumType::lan8032))
1007 {
1008 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1009 {
1010 phosphor::logging::log<phosphor::logging::level::ERR>(
1011 "ipmiOEMSetUser2Activation: DHCP enabled .");
1012 return ipmi::response(ipmi::ccCommandNotAvailable);
1013 }
1014 }
1015 }
1016 }
1017 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1018 if (ipmi::ccSuccess ==
1019 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1020 {
1021 if (enabledUsers > 1)
1022 {
1023 phosphor::logging::log<phosphor::logging::level::ERR>(
1024 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1025 return ipmi::response(ipmi::ccCommandNotAvailable);
1026 }
1027 // Check the user 2 is enabled or not
1028 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1029 if (userState == true)
1030 {
1031 phosphor::logging::log<phosphor::logging::level::ERR>(
1032 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1033 return ipmi::response(ipmi::ccCommandNotAvailable);
1034 }
1035 }
1036 else
1037 {
1038 return ipmi::response(ipmi::ccUnspecifiedError);
1039 }
1040
1041#if BYTE_ORDER == LITTLE_ENDIAN
1042 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1043#endif
1044#if BYTE_ORDER == BIG_ENDIAN
1045 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1046#endif
1047
1048 if (ipmi::ccSuccess ==
1049 ipmiUserSetUserName(ipmiDefaultUserId,
1050 reinterpret_cast<const char*>(userName.data())))
1051 {
1052 if (ipmi::ccSuccess ==
1053 ipmiUserSetUserPassword(
1054 ipmiDefaultUserId,
1055 reinterpret_cast<const char*>(userPassword.data())))
1056 {
1057 if (ipmi::ccSuccess ==
1058 ipmiUserSetPrivilegeAccess(
1059 ipmiDefaultUserId,
1060 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1061 privAccess, true))
1062 {
1063 phosphor::logging::log<phosphor::logging::level::INFO>(
1064 "ipmiOEMSetUser2Activation: user created successfully ");
1065 return ipmi::responseSuccess();
1066 }
1067 }
1068 // we need to delete the default user id which added in this command as
1069 // password / priv setting is failed.
1070 ipmiUserSetUserName(ipmiDefaultUserId, "");
1071 phosphor::logging::log<phosphor::logging::level::ERR>(
1072 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1073 }
1074 else
1075 {
1076 phosphor::logging::log<phosphor::logging::level::ERR>(
1077 "ipmiOEMSetUser2Activation: Setting username failed.");
1078 }
1079
1080 return ipmi::response(ipmi::ccCommandNotAvailable);
1081}
1082
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301083/** @brief implementes executing the linux command
1084 * @param[in] linux command
1085 * @returns status
1086 */
1087
1088static uint8_t executeCmd(const char* path)
1089{
1090 boost::process::child execProg(path);
1091 execProg.wait();
1092
1093 int retCode = execProg.exit_code();
1094 if (retCode)
1095 {
1096 return ipmi::ccUnspecifiedError;
1097 }
1098 return ipmi::ccSuccess;
1099}
1100
1101/** @brief implementes ASD Security event logging
1102 * @param[in] Event message string
1103 * @param[in] Event Severity
1104 * @returns status
1105 */
1106
1107static void atScaleDebugEventlog(std::string msg, int severity)
1108{
1109 std::string eventStr = "OpenBMC.0.1." + msg;
1110 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1111 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1112 eventStr.c_str(), NULL);
1113}
1114
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301115/** @brief implementes setting password for special user
1116 * @param[in] specialUserIndex
1117 * @param[in] userPassword - new password in 20 bytes
1118 * @returns ipmi completion code.
1119 */
1120ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1121 uint8_t specialUserIndex,
1122 std::vector<uint8_t> userPassword)
1123{
1124 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301125 ipmi_ret_t status = ipmi::ccSuccess;
1126
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301127 try
1128 {
1129 getChannelInfo(ctx->channel, chInfo);
1130 }
1131 catch (sdbusplus::exception_t& e)
1132 {
1133 phosphor::logging::log<phosphor::logging::level::ERR>(
1134 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1135 phosphor::logging::entry("MSG: %s", e.description()));
1136 return ipmi::responseUnspecifiedError();
1137 }
1138 if (chInfo.mediumType !=
1139 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1140 {
1141 phosphor::logging::log<phosphor::logging::level::ERR>(
1142 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1143 "interface");
1144 return ipmi::responseCommandNotAvailable();
1145 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301146
1147 // 0 for root user and 1 for AtScaleDebug is allowed
1148 if (specialUserIndex >
1149 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301150 {
1151 phosphor::logging::log<phosphor::logging::level::ERR>(
1152 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1153 return ipmi::responseParmOutOfRange();
1154 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301155 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301156 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301157 constexpr uint8_t minPasswordSizeRequired = 6;
1158 std::string passwd;
1159 if (userPassword.size() < minPasswordSizeRequired ||
1160 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1161 {
1162 return ipmi::responseReqDataLenInvalid();
1163 }
1164 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1165 userPassword.size());
1166 if (specialUserIndex ==
1167 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1168 {
1169 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1170
1171 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1172 }
1173 else
1174 {
1175 status = ipmiSetSpecialUserPassword("root", passwd);
1176 }
1177 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301178 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301179 else
1180 {
1181 if (specialUserIndex ==
1182 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1183 {
1184 status = executeCmd("passwd -d root");
1185 }
1186 else
1187 {
1188
1189 status = executeCmd("passwd -d asdbg");
1190
1191 if (status == 0)
1192 {
1193 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1194 LOG_INFO);
1195 }
1196 }
1197 return ipmi::response(status);
1198 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301199}
1200
Kuiying Wang45f04982018-12-26 09:23:08 +08001201namespace ledAction
1202{
1203using namespace sdbusplus::xyz::openbmc_project::Led::server;
1204std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001205 {Physical::Action::Off, 0},
1206 {Physical::Action::On, 2},
1207 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001208
1209std::map<uint8_t, std::string> offsetObjPath = {
1210 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1211
1212} // namespace ledAction
1213
1214int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1215 const std::string& objPath, uint8_t& state)
1216{
1217 try
1218 {
1219 std::string service = getService(bus, intf, objPath);
1220 Value stateValue =
1221 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001222 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001223 state = ledAction::actionDbusToIpmi.at(
1224 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1225 convertActionFromString(strState));
1226 }
1227 catch (sdbusplus::exception::SdBusError& e)
1228 {
1229 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1230 return -1;
1231 }
1232 return 0;
1233}
1234
1235ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1236 ipmi_request_t request, ipmi_response_t response,
1237 ipmi_data_len_t dataLen, ipmi_context_t context)
1238{
1239 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1240 // LED Status
1241 //[1:0] = Reserved
1242 //[3:2] = Status(Amber)
1243 //[5:4] = Status(Green)
1244 //[7:6] = System Identify
1245 // Status definitions:
1246 // 00b = Off
1247 // 01b = Blink
1248 // 10b = On
1249 // 11b = invalid
1250 if (*dataLen != 0)
1251 {
1252 phosphor::logging::log<phosphor::logging::level::ERR>(
1253 "oem_get_led_status: invalid input len!");
1254 *dataLen = 0;
1255 return IPMI_CC_REQ_DATA_LEN_INVALID;
1256 }
1257
1258 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1259 *resp = 0;
1260 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001261 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001262 for (auto it = ledAction::offsetObjPath.begin();
1263 it != ledAction::offsetObjPath.end(); ++it)
1264 {
1265 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001266 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001267 {
1268 phosphor::logging::log<phosphor::logging::level::ERR>(
1269 "oem_get_led_status: fail to get ID LED status!");
1270 return IPMI_CC_UNSPECIFIED_ERROR;
1271 }
1272 *resp |= state << it->first;
1273 }
1274
1275 *dataLen = sizeof(*resp);
1276 return IPMI_CC_OK;
1277}
1278
Yong Li23737fe2019-02-19 08:49:55 +08001279ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1280 ipmi_request_t request,
1281 ipmi_response_t response,
1282 ipmi_data_len_t dataLen,
1283 ipmi_context_t context)
1284{
1285 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1286 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1287
1288 if (*dataLen == 0)
1289 {
1290 phosphor::logging::log<phosphor::logging::level::ERR>(
1291 "CfgHostSerial: invalid input len!",
1292 phosphor::logging::entry("LEN=%d", *dataLen));
1293 return IPMI_CC_REQ_DATA_LEN_INVALID;
1294 }
1295
1296 switch (req->command)
1297 {
1298 case getHostSerialCfgCmd:
1299 {
1300 if (*dataLen != 1)
1301 {
1302 phosphor::logging::log<phosphor::logging::level::ERR>(
1303 "CfgHostSerial: invalid input len!");
1304 *dataLen = 0;
1305 return IPMI_CC_REQ_DATA_LEN_INVALID;
1306 }
1307
1308 *dataLen = 0;
1309
1310 boost::process::ipstream is;
1311 std::vector<std::string> data;
1312 std::string line;
1313 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1314 boost::process::std_out > is);
1315
1316 while (c1.running() && std::getline(is, line) && !line.empty())
1317 {
1318 data.push_back(line);
1319 }
1320
1321 c1.wait();
1322 if (c1.exit_code())
1323 {
1324 phosphor::logging::log<phosphor::logging::level::ERR>(
1325 "CfgHostSerial:: error on execute",
1326 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1327 // Using the default value
1328 *resp = 0;
1329 }
1330 else
1331 {
1332 if (data.size() != 1)
1333 {
1334 phosphor::logging::log<phosphor::logging::level::ERR>(
1335 "CfgHostSerial:: error on read env");
1336 return IPMI_CC_UNSPECIFIED_ERROR;
1337 }
1338 try
1339 {
1340 unsigned long tmp = std::stoul(data[0]);
1341 if (tmp > std::numeric_limits<uint8_t>::max())
1342 {
1343 throw std::out_of_range("Out of range");
1344 }
1345 *resp = static_cast<uint8_t>(tmp);
1346 }
1347 catch (const std::invalid_argument& e)
1348 {
1349 phosphor::logging::log<phosphor::logging::level::ERR>(
1350 "invalid config ",
1351 phosphor::logging::entry("ERR=%s", e.what()));
1352 return IPMI_CC_UNSPECIFIED_ERROR;
1353 }
1354 catch (const std::out_of_range& e)
1355 {
1356 phosphor::logging::log<phosphor::logging::level::ERR>(
1357 "out_of_range config ",
1358 phosphor::logging::entry("ERR=%s", e.what()));
1359 return IPMI_CC_UNSPECIFIED_ERROR;
1360 }
1361 }
1362
1363 *dataLen = 1;
1364 break;
1365 }
1366 case setHostSerialCfgCmd:
1367 {
1368 if (*dataLen != sizeof(CfgHostSerialReq))
1369 {
1370 phosphor::logging::log<phosphor::logging::level::ERR>(
1371 "CfgHostSerial: invalid input len!");
1372 *dataLen = 0;
1373 return IPMI_CC_REQ_DATA_LEN_INVALID;
1374 }
1375
1376 *dataLen = 0;
1377
1378 if (req->parameter > HostSerialCfgParamMax)
1379 {
1380 phosphor::logging::log<phosphor::logging::level::ERR>(
1381 "CfgHostSerial: invalid input!");
1382 return IPMI_CC_INVALID_FIELD_REQUEST;
1383 }
1384
1385 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1386 std::to_string(req->parameter));
1387
1388 c1.wait();
1389 if (c1.exit_code())
1390 {
1391 phosphor::logging::log<phosphor::logging::level::ERR>(
1392 "CfgHostSerial:: error on execute",
1393 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1394 return IPMI_CC_UNSPECIFIED_ERROR;
1395 }
1396 break;
1397 }
1398 default:
1399 phosphor::logging::log<phosphor::logging::level::ERR>(
1400 "CfgHostSerial: invalid input!");
1401 *dataLen = 0;
1402 return IPMI_CC_INVALID_FIELD_REQUEST;
1403 }
1404
1405 return IPMI_CC_OK;
1406}
1407
James Feist91244a62019-02-19 15:04:54 -08001408constexpr const char* thermalModeInterface =
1409 "xyz.openbmc_project.Control.ThermalMode";
1410constexpr const char* thermalModePath =
1411 "/xyz/openbmc_project/control/thermal_mode";
1412
1413bool getFanProfileInterface(
1414 sdbusplus::bus::bus& bus,
1415 boost::container::flat_map<
1416 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1417{
1418 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1419 "GetAll");
1420 call.append(thermalModeInterface);
1421 try
1422 {
1423 auto data = bus.call(call);
1424 data.read(resp);
1425 }
1426 catch (sdbusplus::exception_t& e)
1427 {
1428 phosphor::logging::log<phosphor::logging::level::ERR>(
1429 "getFanProfileInterface: can't get thermal mode!",
1430 phosphor::logging::entry("ERR=%s", e.what()));
1431 return false;
1432 }
1433 return true;
1434}
1435
anil kumar appanaf945eee2019-09-25 23:29:11 +00001436/**@brief implements the OEM set fan config.
1437 * @param selectedFanProfile - fan profile to enable
1438 * @param reserved1
1439 * @param performanceMode - Performance/Acoustic mode
1440 * @param reserved2
1441 * @param setPerformanceMode - set Performance/Acoustic mode
1442 * @param setFanProfile - set fan profile
1443 *
1444 * @return IPMI completion code.
1445 **/
1446ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1447
1448 uint2_t reserved1, bool performanceMode,
1449 uint3_t reserved2, bool setPerformanceMode,
Joshi-Mansi619186d2020-01-27 19:16:03 +05301450 bool setFanProfile,
1451 std::optional<uint8_t> dimmGroupId,
1452 std::optional<uint32_t> dimmPresenceBitmap)
James Feist91244a62019-02-19 15:04:54 -08001453{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001454 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001455 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001456 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001457 }
Joshi-Mansi619186d2020-01-27 19:16:03 +05301458
1459 if (dimmGroupId)
1460 {
1461 if (*dimmGroupId >= maxCPUNum)
1462 {
1463 return ipmi::responseInvalidFieldRequest();
1464 }
1465 if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1)))
1466 {
1467 return ipmi::responseInvalidFieldRequest();
1468 }
1469 }
1470
James Feist91244a62019-02-19 15:04:54 -08001471 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001472 boost::container::flat_map<
1473 std::string, std::variant<std::vector<std::string>, std::string>>
1474 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001475 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1476 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001477 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001478 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001479 }
1480
1481 std::vector<std::string>* supported =
1482 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1483 if (supported == nullptr)
1484 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001485 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001486 }
1487 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001488 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001489 {
James Feist91244a62019-02-19 15:04:54 -08001490 if (performanceMode)
1491 {
1492
1493 if (std::find(supported->begin(), supported->end(),
1494 "Performance") != supported->end())
1495 {
1496 mode = "Performance";
1497 }
1498 }
1499 else
1500 {
James Feist91244a62019-02-19 15:04:54 -08001501 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1502 supported->end())
1503 {
1504 mode = "Acoustic";
1505 }
1506 }
1507 if (mode.empty())
1508 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001509 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001510 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001511
1512 try
1513 {
1514 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1515 thermalModeInterface, "Current", mode);
1516 }
1517 catch (sdbusplus::exception_t& e)
1518 {
1519 phosphor::logging::log<phosphor::logging::level::ERR>(
1520 "ipmiOEMSetFanConfig: can't set thermal mode!",
1521 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1522 return ipmi::responseResponseError();
1523 }
James Feist91244a62019-02-19 15:04:54 -08001524 }
1525
anil kumar appanaf945eee2019-09-25 23:29:11 +00001526 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001527}
1528
James Feist5b693632019-07-09 09:06:09 -07001529ipmi::RspType<uint8_t, // profile support map
1530 uint8_t, // fan control profile enable
1531 uint8_t, // flags
1532 uint32_t // dimm presence bit map
1533 >
1534 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001535{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301536 if (dimmGroupId >= maxCPUNum)
1537 {
1538 return ipmi::responseInvalidFieldRequest();
1539 }
1540
1541 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1542
1543 if (!cpuStatus)
1544 {
1545 return ipmi::responseInvalidFieldRequest();
1546 }
1547
James Feist91244a62019-02-19 15:04:54 -08001548 boost::container::flat_map<
1549 std::string, std::variant<std::vector<std::string>, std::string>>
1550 profileData;
1551
Vernon Mauery15419dd2019-05-24 09:40:30 -07001552 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1553 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001554 {
James Feist5b693632019-07-09 09:06:09 -07001555 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001556 }
1557
1558 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1559
1560 if (current == nullptr)
1561 {
1562 phosphor::logging::log<phosphor::logging::level::ERR>(
1563 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001564 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001565 }
1566 bool performance = (*current == "Performance");
1567
James Feist5b693632019-07-09 09:06:09 -07001568 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001569 if (performance)
1570 {
James Feist5b693632019-07-09 09:06:09 -07001571 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001572 }
1573
jayaprakash Mutyala4b1552d2020-02-11 12:07:29 +00001574 constexpr uint8_t fanControlDefaultProfile = 0x80;
1575 constexpr uint8_t fanControlProfileState = 0x00;
1576 constexpr uint32_t dimmPresenceBitmap = 0x00;
1577
1578 return ipmi::responseSuccess(fanControlDefaultProfile,
1579 fanControlProfileState, flags,
1580 dimmPresenceBitmap);
James Feist91244a62019-02-19 15:04:54 -08001581}
James Feist5f957ca2019-03-14 15:33:55 -07001582constexpr const char* cfmLimitSettingPath =
1583 "/xyz/openbmc_project/control/cfm_limit";
1584constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001585constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001586constexpr const size_t legacyPCHSensorNumber = 0x22;
1587constexpr const char* exitAirPathName = "Exit_Air";
1588constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001589constexpr const char* pidConfigurationIface =
1590 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001591
James Feist09f6b602019-08-08 11:30:03 -07001592static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001593{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001594 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001595 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001596 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1597 "/xyz/openbmc_project/object_mapper",
1598 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001599
James Feistacc8a4e2019-04-02 14:23:57 -07001600 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001601 std::string path;
1602 GetSubTreeType resp;
1603 try
1604 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001605 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001606 reply.read(resp);
1607 }
1608 catch (sdbusplus::exception_t&)
1609 {
1610 phosphor::logging::log<phosphor::logging::level::ERR>(
1611 "ipmiOEMGetFscParameter: mapper error");
1612 };
James Feist09f6b602019-08-08 11:30:03 -07001613 auto config =
1614 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1615 return pair.first.find(name) != std::string::npos;
1616 });
James Feistfaa4f222019-03-21 16:21:55 -07001617 if (config != resp.end())
1618 {
1619 path = std::move(config->first);
1620 }
1621 return path;
1622}
James Feist5f957ca2019-03-14 15:33:55 -07001623
James Feistacc8a4e2019-04-02 14:23:57 -07001624// flat map to make alphabetical
1625static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1626{
1627 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001628 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001629 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001630 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1631 "/xyz/openbmc_project/object_mapper",
1632 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001633
1634 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1635 GetSubTreeType resp;
1636
1637 try
1638 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001639 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001640 reply.read(resp);
1641 }
1642 catch (sdbusplus::exception_t&)
1643 {
1644 phosphor::logging::log<phosphor::logging::level::ERR>(
1645 "getFanConfigPaths: mapper error");
1646 };
1647 for (const auto& [path, objects] : resp)
1648 {
1649 if (objects.empty())
1650 {
1651 continue; // should be impossible
1652 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001653
1654 try
1655 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001656 ret.emplace(path,
1657 getAllDbusProperties(*dbus, objects[0].first, path,
1658 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001659 }
1660 catch (sdbusplus::exception_t& e)
1661 {
1662 phosphor::logging::log<phosphor::logging::level::ERR>(
1663 "getPidConfigs: can't get DbusProperties!",
1664 phosphor::logging::entry("ERR=%s", e.what()));
1665 }
James Feistacc8a4e2019-04-02 14:23:57 -07001666 }
1667 return ret;
1668}
1669
1670ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1671{
1672 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1673 if (data.empty())
1674 {
1675 return ipmi::responseResponseError();
1676 }
1677 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1678 for (const auto& [_, pid] : data)
1679 {
1680 auto findClass = pid.find("Class");
1681 if (findClass == pid.end())
1682 {
1683 phosphor::logging::log<phosphor::logging::level::ERR>(
1684 "ipmiOEMGetFscParameter: found illegal pid "
1685 "configurations");
1686 return ipmi::responseResponseError();
1687 }
1688 std::string type = std::get<std::string>(findClass->second);
1689 if (type == "fan")
1690 {
1691 auto findOutLimit = pid.find("OutLimitMin");
1692 if (findOutLimit == pid.end())
1693 {
1694 phosphor::logging::log<phosphor::logging::level::ERR>(
1695 "ipmiOEMGetFscParameter: found illegal pid "
1696 "configurations");
1697 return ipmi::responseResponseError();
1698 }
1699 // get the min out of all the offsets
1700 minOffset = std::min(
1701 minOffset,
1702 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1703 }
1704 }
1705 if (minOffset == std::numeric_limits<uint8_t>::max())
1706 {
1707 phosphor::logging::log<phosphor::logging::level::ERR>(
1708 "ipmiOEMGetFscParameter: found no fan configurations!");
1709 return ipmi::responseResponseError();
1710 }
1711
1712 return ipmi::responseSuccess(minOffset);
1713}
1714
1715ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1716{
1717 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1718 if (data.empty())
1719 {
1720
1721 phosphor::logging::log<phosphor::logging::level::ERR>(
1722 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1723 return ipmi::responseResponseError();
1724 }
1725
Vernon Mauery15419dd2019-05-24 09:40:30 -07001726 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001727 bool found = false;
1728 for (const auto& [path, pid] : data)
1729 {
1730 auto findClass = pid.find("Class");
1731 if (findClass == pid.end())
1732 {
1733
1734 phosphor::logging::log<phosphor::logging::level::ERR>(
1735 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1736 "configurations");
1737 return ipmi::responseResponseError();
1738 }
1739 std::string type = std::get<std::string>(findClass->second);
1740 if (type == "fan")
1741 {
1742 auto findOutLimit = pid.find("OutLimitMin");
1743 if (findOutLimit == pid.end())
1744 {
1745
1746 phosphor::logging::log<phosphor::logging::level::ERR>(
1747 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1748 "configurations");
1749 return ipmi::responseResponseError();
1750 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001751 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001752 path, pidConfigurationIface, "OutLimitMin",
1753 static_cast<double>(offset));
1754 found = true;
1755 }
1756 }
1757 if (!found)
1758 {
1759 phosphor::logging::log<phosphor::logging::level::ERR>(
1760 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1761 return ipmi::responseResponseError();
1762 }
1763
1764 return ipmi::responseSuccess();
1765}
1766
1767ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1768 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001769{
1770 constexpr const size_t disableLimiting = 0x0;
1771
Vernon Mauery15419dd2019-05-24 09:40:30 -07001772 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001773 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001774 {
James Feist09f6b602019-08-08 11:30:03 -07001775 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001776 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001777 {
James Feist09f6b602019-08-08 11:30:03 -07001778 pathName = exitAirPathName;
1779 }
1780 else if (param1 == legacyPCHSensorNumber)
1781 {
1782 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001783 }
1784 else
1785 {
James Feistacc8a4e2019-04-02 14:23:57 -07001786 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001787 }
James Feist09f6b602019-08-08 11:30:03 -07001788 std::string path = getConfigPath(pathName);
1789 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1790 pidConfigurationIface, "SetPoint",
1791 static_cast<double>(param2));
1792 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001793 }
James Feistacc8a4e2019-04-02 14:23:57 -07001794 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001795 {
James Feistacc8a4e2019-04-02 14:23:57 -07001796 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001797
1798 // must be greater than 50 based on eps
1799 if (cfm < 50 && cfm != disableLimiting)
1800 {
James Feistacc8a4e2019-04-02 14:23:57 -07001801 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001802 }
1803
1804 try
1805 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001806 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001807 cfmLimitIface, "Limit",
1808 static_cast<double>(cfm));
1809 }
1810 catch (sdbusplus::exception_t& e)
1811 {
1812 phosphor::logging::log<phosphor::logging::level::ERR>(
1813 "ipmiOEMSetFscParameter: can't set cfm setting!",
1814 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001815 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001816 }
James Feistacc8a4e2019-04-02 14:23:57 -07001817 return ipmi::responseSuccess();
1818 }
1819 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1820 {
1821 constexpr const size_t maxDomainCount = 8;
1822 uint8_t requestedDomainMask = param1;
1823 boost::container::flat_map data = getPidConfigs();
1824 if (data.empty())
1825 {
1826
1827 phosphor::logging::log<phosphor::logging::level::ERR>(
1828 "ipmiOEMSetFscParameter: found no pid configurations!");
1829 return ipmi::responseResponseError();
1830 }
1831 size_t count = 0;
1832 for (const auto& [path, pid] : data)
1833 {
1834 auto findClass = pid.find("Class");
1835 if (findClass == pid.end())
1836 {
1837
1838 phosphor::logging::log<phosphor::logging::level::ERR>(
1839 "ipmiOEMSetFscParameter: found illegal pid "
1840 "configurations");
1841 return ipmi::responseResponseError();
1842 }
1843 std::string type = std::get<std::string>(findClass->second);
1844 if (type == "fan")
1845 {
1846 if (requestedDomainMask & (1 << count))
1847 {
1848 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001849 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001850 pidConfigurationIface, "OutLimitMax",
1851 static_cast<double>(param2));
1852 }
1853 count++;
1854 }
1855 }
1856 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001857 }
1858 else
1859 {
1860 // todo other command parts possibly
1861 // tcontrol is handled in peci now
1862 // fan speed offset not implemented yet
1863 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001864 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001865 }
1866}
1867
James Feistacc8a4e2019-04-02 14:23:57 -07001868ipmi::RspType<
1869 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1870 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001871{
James Feist09f6b602019-08-08 11:30:03 -07001872 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001873
Vernon Mauery15419dd2019-05-24 09:40:30 -07001874 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001875 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001876 {
James Feistacc8a4e2019-04-02 14:23:57 -07001877 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001878 {
James Feistacc8a4e2019-04-02 14:23:57 -07001879 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001880 }
1881
James Feist09f6b602019-08-08 11:30:03 -07001882 std::string pathName;
1883
1884 if (*param == legacyExitAirSensorNumber)
1885 {
1886 pathName = exitAirPathName;
1887 }
1888 else if (*param == legacyPCHSensorNumber)
1889 {
1890 pathName = pchPathName;
1891 }
1892 else
James Feistfaa4f222019-03-21 16:21:55 -07001893 {
James Feistacc8a4e2019-04-02 14:23:57 -07001894 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001895 }
James Feist09f6b602019-08-08 11:30:03 -07001896
1897 uint8_t setpoint = legacyDefaultSetpoint;
1898 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001899 if (path.size())
1900 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001901 Value val = ipmi::getDbusProperty(
1902 *dbus, "xyz.openbmc_project.EntityManager", path,
1903 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001904 setpoint = std::floor(std::get<double>(val) + 0.5);
1905 }
1906
1907 // old implementation used to return the "default" and current, we
1908 // don't make the default readily available so just make both the
1909 // same
James Feistfaa4f222019-03-21 16:21:55 -07001910
James Feistacc8a4e2019-04-02 14:23:57 -07001911 return ipmi::responseSuccess(
1912 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001913 }
James Feistacc8a4e2019-04-02 14:23:57 -07001914 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1915 {
1916 constexpr const size_t maxDomainCount = 8;
1917
1918 if (!param)
1919 {
1920 return ipmi::responseReqDataLenInvalid();
1921 }
1922 uint8_t requestedDomain = *param;
1923 if (requestedDomain >= maxDomainCount)
1924 {
1925 return ipmi::responseInvalidFieldRequest();
1926 }
1927
1928 boost::container::flat_map data = getPidConfigs();
1929 if (data.empty())
1930 {
1931 phosphor::logging::log<phosphor::logging::level::ERR>(
1932 "ipmiOEMGetFscParameter: found no pid configurations!");
1933 return ipmi::responseResponseError();
1934 }
1935 size_t count = 0;
1936 for (const auto& [_, pid] : data)
1937 {
1938 auto findClass = pid.find("Class");
1939 if (findClass == pid.end())
1940 {
1941 phosphor::logging::log<phosphor::logging::level::ERR>(
1942 "ipmiOEMGetFscParameter: found illegal pid "
1943 "configurations");
1944 return ipmi::responseResponseError();
1945 }
1946 std::string type = std::get<std::string>(findClass->second);
1947 if (type == "fan")
1948 {
1949 if (requestedDomain == count)
1950 {
1951 auto findOutLimit = pid.find("OutLimitMax");
1952 if (findOutLimit == pid.end())
1953 {
1954 phosphor::logging::log<phosphor::logging::level::ERR>(
1955 "ipmiOEMGetFscParameter: found illegal pid "
1956 "configurations");
1957 return ipmi::responseResponseError();
1958 }
1959
1960 return ipmi::responseSuccess(
1961 static_cast<uint8_t>(std::floor(
1962 std::get<double>(findOutLimit->second) + 0.5)));
1963 }
1964 else
1965 {
1966 count++;
1967 }
1968 }
1969 }
1970
1971 return ipmi::responseInvalidFieldRequest();
1972 }
1973 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001974 {
1975
1976 /*
1977 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001978 previous behavior didn't seem to prevent this, ignore the check for
1979 now.
James Feist5f957ca2019-03-14 15:33:55 -07001980
James Feistacc8a4e2019-04-02 14:23:57 -07001981 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001982 {
1983 phosphor::logging::log<phosphor::logging::level::ERR>(
1984 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001985 return IPMI_CC_REQ_DATA_LEN_INVALID;
1986 }
1987 */
1988 Value cfmLimit;
1989 Value cfmMaximum;
1990 try
1991 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001992 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001993 cfmLimitSettingPath, cfmLimitIface,
1994 "Limit");
1995 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001996 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001997 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1998 }
1999 catch (sdbusplus::exception_t& e)
2000 {
2001 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002002 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002003 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002004 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002005 }
2006
James Feistacc8a4e2019-04-02 14:23:57 -07002007 double cfmMax = std::get<double>(cfmMaximum);
2008 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002009
James Feistacc8a4e2019-04-02 14:23:57 -07002010 cfmLim = std::floor(cfmLim + 0.5);
2011 cfmMax = std::floor(cfmMax + 0.5);
2012 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2013 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002014
James Feistacc8a4e2019-04-02 14:23:57 -07002015 return ipmi::responseSuccess(
2016 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002017 }
James Feistacc8a4e2019-04-02 14:23:57 -07002018
James Feist5f957ca2019-03-14 15:33:55 -07002019 else
2020 {
2021 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002022 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002023 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002024 }
2025}
2026
Cheng C Yang773703a2019-08-15 09:41:11 +08002027using crConfigVariant =
2028 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2029
2030int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2031 const crConfigVariant& value,
2032 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2033{
2034 boost::system::error_code ec;
2035 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002036 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002037 "/xyz/openbmc_project/control/power_supply_redundancy",
2038 "org.freedesktop.DBus.Properties", "Set",
2039 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2040 if (ec)
2041 {
2042 phosphor::logging::log<phosphor::logging::level::ERR>(
2043 "Failed to set dbus property to cold redundancy");
2044 return -1;
2045 }
2046
2047 return 0;
2048}
2049
2050int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2051 crConfigVariant& value,
Yong Li19445ab2019-12-20 18:25:29 +08002052 const std::string& service = "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002053 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2054{
2055 boost::system::error_code ec;
2056 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002057 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002058 "/xyz/openbmc_project/control/power_supply_redundancy",
2059 "org.freedesktop.DBus.Properties", "Get",
2060 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2061 if (ec)
2062 {
2063 phosphor::logging::log<phosphor::logging::level::ERR>(
2064 "Failed to get dbus property to cold redundancy");
2065 return -1;
2066 }
2067 return 0;
2068}
2069
2070uint8_t getPSUCount(void)
2071{
2072 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2073 ipmi::Value num;
2074 try
2075 {
2076 num = ipmi::getDbusProperty(
2077 *dbus, "xyz.openbmc_project.PSURedundancy",
2078 "/xyz/openbmc_project/control/power_supply_redundancy",
2079 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2080 }
2081 catch (sdbusplus::exception_t& e)
2082 {
2083 phosphor::logging::log<phosphor::logging::level::ERR>(
2084 "Failed to get PSUNumber property from dbus interface");
2085 return 0;
2086 }
2087 uint8_t* pNum = std::get_if<uint8_t>(&num);
2088 if (!pNum)
2089 {
2090 phosphor::logging::log<phosphor::logging::level::ERR>(
2091 "Error to get PSU Number");
2092 return 0;
2093 }
2094 return *pNum;
2095}
2096
2097bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2098{
2099 if (conf.size() < num)
2100 {
2101 phosphor::logging::log<phosphor::logging::level::ERR>(
2102 "Invalid PSU Ranking");
2103 return false;
2104 }
2105 std::set<uint8_t> confSet;
2106 for (uint8_t i = 0; i < num; i++)
2107 {
2108 if (conf[i] > num)
2109 {
2110 phosphor::logging::log<phosphor::logging::level::ERR>(
2111 "PSU Ranking is larger than current PSU number");
2112 return false;
2113 }
2114 confSet.emplace(conf[i]);
2115 }
2116
2117 if (confSet.size() != num)
2118 {
2119 phosphor::logging::log<phosphor::logging::level::ERR>(
2120 "duplicate PSU Ranking");
2121 return false;
2122 }
2123 return true;
2124}
2125
2126enum class crParameter
2127{
2128 crStatus = 0,
2129 crFeature = 1,
2130 rotationFeature = 2,
2131 rotationAlgo = 3,
2132 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002133 numOfPSU = 5,
2134 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002135};
2136
2137constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2138static const constexpr uint32_t oneDay = 0x15180;
2139static const constexpr uint32_t oneMonth = 0xf53700;
2140static const constexpr uint8_t userSpecific = 0x01;
2141static const constexpr uint8_t crSetCompleted = 0;
2142ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2143 uint8_t parameter,
2144 ipmi::message::Payload& payload)
2145{
2146 switch (static_cast<crParameter>(parameter))
2147 {
2148 case crParameter::crFeature:
2149 {
2150 uint8_t param1;
2151 if (payload.unpack(param1) || !payload.fullyUnpacked())
2152 {
2153 return ipmi::responseReqDataLenInvalid();
2154 }
2155 // ColdRedundancy Enable can only be true or flase
2156 if (param1 > 1)
2157 {
2158 return ipmi::responseInvalidFieldRequest();
2159 }
2160 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2161 static_cast<bool>(param1)))
2162 {
2163 return ipmi::responseResponseError();
2164 }
2165 break;
2166 }
2167 case crParameter::rotationFeature:
2168 {
2169 uint8_t param1;
2170 if (payload.unpack(param1) || !payload.fullyUnpacked())
2171 {
2172 return ipmi::responseReqDataLenInvalid();
2173 }
2174 // Rotation Enable can only be true or false
2175 if (param1 > 1)
2176 {
2177 return ipmi::responseInvalidFieldRequest();
2178 }
2179 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2180 {
2181 return ipmi::responseResponseError();
2182 }
2183 break;
2184 }
2185 case crParameter::rotationAlgo:
2186 {
2187 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2188 std::string algoName;
2189 uint8_t param1;
2190 if (payload.unpack(param1))
2191 {
2192 return ipmi::responseReqDataLenInvalid();
2193 }
2194 switch (param1)
2195 {
2196 case 0:
2197 algoName = "xyz.openbmc_project.Control."
2198 "PowerSupplyRedundancy.Algo.bmcSpecific";
2199 break;
2200 case 1:
2201 algoName = "xyz.openbmc_project.Control."
2202 "PowerSupplyRedundancy.Algo.userSpecific";
2203 break;
2204 default:
2205 return ipmi::responseInvalidFieldRequest();
2206 }
2207 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2208 {
2209 return ipmi::responseResponseError();
2210 }
2211
2212 uint8_t numberOfPSU = getPSUCount();
2213 if (!numberOfPSU)
2214 {
2215 return ipmi::responseResponseError();
2216 }
2217 std::vector<uint8_t> rankOrder;
2218
2219 if (param1 == userSpecific)
2220 {
2221 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2222 {
2223 ipmi::responseReqDataLenInvalid();
2224 }
Yong Li83315132019-10-23 17:42:24 +08002225 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002226 {
2227 return ipmi::responseReqDataLenInvalid();
2228 }
2229
2230 if (!validateCRAlgo(rankOrder, numberOfPSU))
2231 {
2232 return ipmi::responseInvalidFieldRequest();
2233 }
2234 }
2235 else
2236 {
2237 if (rankOrder.size() > 0)
2238 {
2239 return ipmi::responseReqDataLenInvalid();
2240 }
2241 for (uint8_t i = 1; i <= numberOfPSU; i++)
2242 {
2243 rankOrder.emplace_back(i);
2244 }
2245 }
2246 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2247 {
2248 return ipmi::responseResponseError();
2249 }
2250 break;
2251 }
2252 case crParameter::rotationPeriod:
2253 {
2254 // Minimum Rotation period is One day (86400 seconds) and Max
2255 // Rotation Period is 6 month (0xf53700 seconds)
2256 uint32_t period;
2257 if (payload.unpack(period) || !payload.fullyUnpacked())
2258 {
2259 return ipmi::responseReqDataLenInvalid();
2260 }
2261 if ((period < oneDay) || (period > oneMonth))
2262 {
2263 return ipmi::responseInvalidFieldRequest();
2264 }
2265 if (setCRConfig(ctx, "PeriodOfRotation", period))
2266 {
2267 return ipmi::responseResponseError();
2268 }
2269 break;
2270 }
2271 default:
2272 {
2273 return ipmi::response(ccParameterNotSupported);
2274 }
2275 }
2276
2277 // TODO Halfwidth needs to set SetInProgress
2278 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002279 std::string("xyz.openbmc_project.Control."
2280 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002281 {
2282 return ipmi::responseResponseError();
2283 }
2284 return ipmi::responseSuccess(crSetCompleted);
2285}
2286
Yong Li83315132019-10-23 17:42:24 +08002287ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002288 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2289{
2290 crConfigVariant value;
2291 switch (static_cast<crParameter>(parameter))
2292 {
2293 case crParameter::crStatus:
2294 {
2295 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2296 {
2297 return ipmi::responseResponseError();
2298 }
2299 std::string* pStatus = std::get_if<std::string>(&value);
2300 if (!pStatus)
2301 {
2302 phosphor::logging::log<phosphor::logging::level::ERR>(
2303 "Error to get ColdRedundancyStatus property");
2304 return ipmi::responseResponseError();
2305 }
2306 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2307 auto status =
2308 server::PowerSupplyRedundancy::convertStatusFromString(
2309 *pStatus);
2310 switch (status)
2311 {
2312 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002313 return ipmi::responseSuccess(parameter,
2314 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002315
2316 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002317 return ipmi::responseSuccess(parameter,
2318 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002319 default:
2320 phosphor::logging::log<phosphor::logging::level::ERR>(
2321 "Error to get valid status");
2322 return ipmi::responseResponseError();
2323 }
2324 }
2325 case crParameter::crFeature:
2326 {
2327 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2328 {
2329 return ipmi::responseResponseError();
2330 }
2331 bool* pResponse = std::get_if<bool>(&value);
2332 if (!pResponse)
2333 {
2334 phosphor::logging::log<phosphor::logging::level::ERR>(
2335 "Error to get ColdRedundancyEnable property");
2336 return ipmi::responseResponseError();
2337 }
2338
Cheng C Yangf41e3342019-09-10 04:47:23 +08002339 return ipmi::responseSuccess(parameter,
2340 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002341 }
2342 case crParameter::rotationFeature:
2343 {
2344 if (getCRConfig(ctx, "RotationEnabled", value))
2345 {
2346 return ipmi::responseResponseError();
2347 }
2348 bool* pResponse = std::get_if<bool>(&value);
2349 if (!pResponse)
2350 {
2351 phosphor::logging::log<phosphor::logging::level::ERR>(
2352 "Error to get RotationEnabled property");
2353 return ipmi::responseResponseError();
2354 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002355 return ipmi::responseSuccess(parameter,
2356 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002357 }
2358 case crParameter::rotationAlgo:
2359 {
2360 if (getCRConfig(ctx, "RotationAlgorithm", value))
2361 {
2362 return ipmi::responseResponseError();
2363 }
2364
2365 std::string* pAlgo = std::get_if<std::string>(&value);
2366 if (!pAlgo)
2367 {
2368 phosphor::logging::log<phosphor::logging::level::ERR>(
2369 "Error to get RotationAlgorithm property");
2370 return ipmi::responseResponseError();
2371 }
Yong Li83315132019-10-23 17:42:24 +08002372 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002373 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2374 auto algo =
2375 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002376
Cheng C Yang773703a2019-08-15 09:41:11 +08002377 switch (algo)
2378 {
2379 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002380 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002381 break;
2382 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002383 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002384 break;
2385 default:
2386 phosphor::logging::log<phosphor::logging::level::ERR>(
2387 "Error to get valid algo");
2388 return ipmi::responseResponseError();
2389 }
2390
2391 if (getCRConfig(ctx, "RotationRankOrder", value))
2392 {
2393 return ipmi::responseResponseError();
2394 }
2395 std::vector<uint8_t>* pResponse =
2396 std::get_if<std::vector<uint8_t>>(&value);
2397 if (!pResponse)
2398 {
2399 phosphor::logging::log<phosphor::logging::level::ERR>(
2400 "Error to get RotationRankOrder property");
2401 return ipmi::responseResponseError();
2402 }
Yong Li83315132019-10-23 17:42:24 +08002403
Cheng C Yang773703a2019-08-15 09:41:11 +08002404 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002405 std::back_inserter(response));
2406
Cheng C Yangf41e3342019-09-10 04:47:23 +08002407 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002408 }
2409 case crParameter::rotationPeriod:
2410 {
2411 if (getCRConfig(ctx, "PeriodOfRotation", value))
2412 {
2413 return ipmi::responseResponseError();
2414 }
2415 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2416 if (!pResponse)
2417 {
2418 phosphor::logging::log<phosphor::logging::level::ERR>(
2419 "Error to get RotationAlgorithm property");
2420 return ipmi::responseResponseError();
2421 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002422 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002423 }
2424 case crParameter::numOfPSU:
2425 {
2426 uint8_t numberOfPSU = getPSUCount();
2427 if (!numberOfPSU)
2428 {
2429 return ipmi::responseResponseError();
2430 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002431 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002432 }
Yong Li19445ab2019-12-20 18:25:29 +08002433 case crParameter::rotationRankOrderEffective:
2434 {
2435 if (getCRConfig(ctx, "RotationRankOrder", value,
2436 "xyz.openbmc_project.PSURedundancy"))
2437 {
2438 return ipmi::responseResponseError();
2439 }
2440 std::vector<uint8_t>* pResponse =
2441 std::get_if<std::vector<uint8_t>>(&value);
2442 if (!pResponse)
2443 {
2444 phosphor::logging::log<phosphor::logging::level::ERR>(
2445 "Error to get effective RotationRankOrder property");
2446 return ipmi::responseResponseError();
2447 }
2448 return ipmi::responseSuccess(parameter, *pResponse);
2449 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002450 default:
2451 {
2452 return ipmi::response(ccParameterNotSupported);
2453 }
2454 }
2455}
2456
Zhu, Yungebe560b02019-04-21 21:19:21 -04002457ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2458 uint8_t faultState,
2459 uint8_t faultGroup,
2460 std::array<uint8_t, 8>& ledStateData)
2461{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002462 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2463 static const std::array<std::string, maxFaultType> faultNames = {
2464 "faultFan", "faultTemp", "faultPower",
2465 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002466
2467 constexpr uint8_t maxFaultSource = 0x4;
2468 constexpr uint8_t skipLEDs = 0xFF;
2469 constexpr uint8_t pinSize = 64;
2470 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002471 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002472
Zhikui Rence4e73f2019-12-06 13:59:47 -08002473 // same pin names need to be defined in dts file
2474 static const std::array<std::array<std::string, groupSize>, groupNum>
2475 faultLedPinNames = {{
2476 "LED_CPU1_CH1_DIMM1_FAULT",
2477 "LED_CPU1_CH1_DIMM2_FAULT",
2478 "LED_CPU1_CH2_DIMM1_FAULT",
2479 "LED_CPU1_CH2_DIMM2_FAULT",
2480 "LED_CPU1_CH3_DIMM1_FAULT",
2481 "LED_CPU1_CH3_DIMM2_FAULT",
2482 "LED_CPU1_CH4_DIMM1_FAULT",
2483 "LED_CPU1_CH4_DIMM2_FAULT",
2484 "LED_CPU1_CH5_DIMM1_FAULT",
2485 "LED_CPU1_CH5_DIMM2_FAULT",
2486 "LED_CPU1_CH6_DIMM1_FAULT",
2487 "LED_CPU1_CH6_DIMM2_FAULT",
2488 "",
2489 "",
2490 "",
2491 "", // end of group1
2492 "LED_CPU2_CH1_DIMM1_FAULT",
2493 "LED_CPU2_CH1_DIMM2_FAULT",
2494 "LED_CPU2_CH2_DIMM1_FAULT",
2495 "LED_CPU2_CH2_DIMM2_FAULT",
2496 "LED_CPU2_CH3_DIMM1_FAULT",
2497 "LED_CPU2_CH3_DIMM2_FAULT",
2498 "LED_CPU2_CH4_DIMM1_FAULT",
2499 "LED_CPU2_CH4_DIMM2_FAULT",
2500 "LED_CPU2_CH5_DIMM1_FAULT",
2501 "LED_CPU2_CH5_DIMM2_FAULT",
2502 "LED_CPU2_CH6_DIMM1_FAULT",
2503 "LED_CPU2_CH6_DIMM2_FAULT",
2504 "",
2505 "",
2506 "",
2507 "", // endof group2
2508 "LED_CPU3_CH1_DIMM1_FAULT",
2509 "LED_CPU3_CH1_DIMM2_FAULT",
2510 "LED_CPU3_CH2_DIMM1_FAULT",
2511 "LED_CPU3_CH2_DIMM2_FAULT",
2512 "LED_CPU3_CH3_DIMM1_FAULT",
2513 "LED_CPU3_CH3_DIMM2_FAULT",
2514 "LED_CPU3_CH4_DIMM1_FAULT",
2515 "LED_CPU3_CH4_DIMM2_FAULT",
2516 "LED_CPU3_CH5_DIMM1_FAULT",
2517 "LED_CPU3_CH5_DIMM2_FAULT",
2518 "LED_CPU3_CH6_DIMM1_FAULT",
2519 "LED_CPU3_CH6_DIMM2_FAULT",
2520 "",
2521 "",
2522 "",
2523 "", // end of group3
2524 "LED_CPU4_CH1_DIMM1_FAULT",
2525 "LED_CPU4_CH1_DIMM2_FAULT",
2526 "LED_CPU4_CH2_DIMM1_FAULT",
2527 "LED_CPU4_CH2_DIMM2_FAULT",
2528 "LED_CPU4_CH3_DIMM1_FAULT",
2529 "LED_CPU4_CH3_DIMM2_FAULT",
2530 "LED_CPU4_CH4_DIMM1_FAULT",
2531 "LED_CPU4_CH4_DIMM2_FAULT",
2532 "LED_CPU4_CH5_DIMM1_FAULT",
2533 "LED_CPU4_CH5_DIMM2_FAULT",
2534 "LED_CPU4_CH6_DIMM1_FAULT",
2535 "LED_CPU4_CH6_DIMM2_FAULT",
2536 "",
2537 "",
2538 "",
2539 "", // end of group4
2540 "LED_FAN1_FAULT",
2541 "LED_FAN2_FAULT",
2542 "LED_FAN3_FAULT",
2543 "LED_FAN4_FAULT",
2544 "LED_FAN5_FAULT",
2545 "LED_FAN6_FAULT",
2546 "LED_FAN7_FAULT",
2547 "LED_FAN8_FAULT",
2548 "",
2549 "",
2550 "",
2551 "",
2552 "",
2553 "",
2554 "",
2555 "" // end of group5
2556 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002557
Zhikui Rence4e73f2019-12-06 13:59:47 -08002558 // Validate the source, fault type --
2559 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2560 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2561 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2562 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2563 // definition differs based on fault type (Byte 2)
2564 // Type Fan=> Group: 0=FanGroupID, FF-not used
2565 // Byte 5-11 00h, not used
2566 // Byte12 FanLedState [7:0]-Fans 7:0
2567 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2568 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2569 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2570 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2571 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2572 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2573 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2574 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002575 if ((sourceId >= maxFaultSource) ||
2576 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2577 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2578 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2579 {
2580 return ipmi::responseParmOutOfRange();
2581 }
2582
Zhikui Rence4e73f2019-12-06 13:59:47 -08002583 size_t pinGroupOffset = 0;
2584 size_t pinGroupMax = pinSize / groupSize;
2585 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002586 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002587 pinGroupOffset = 4;
2588 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002589 }
2590
2591 switch (RemoteFaultType(faultType))
2592 {
2593 case (RemoteFaultType::fan):
2594 case (RemoteFaultType::memory):
2595 {
2596 if (faultGroup == skipLEDs)
2597 {
2598 return ipmi::responseSuccess();
2599 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002600 // calculate led state bit filed count, each byte has 8bits
2601 // the maximum bits will be 8 * 8 bits
2602 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002603
2604 // assemble ledState
2605 uint64_t ledState = 0;
2606 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002607 for (int i = 0; i < sizeof(ledStateData); i++)
2608 {
2609 ledState = (uint64_t)(ledState << 8);
2610 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2611 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002612 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002613
Zhikui Rence4e73f2019-12-06 13:59:47 -08002614 for (int group = 0; group < pinGroupMax; group++)
2615 {
2616 for (int i = 0; i < groupSize; i++)
2617 { // skip non-existing pins
2618 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2619 {
2620 continue;
2621 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002622
Zhikui Rence4e73f2019-12-06 13:59:47 -08002623 gpiod::line line = gpiod::find_line(
2624 faultLedPinNames[group + pinGroupOffset][i]);
2625 if (!line)
2626 {
2627 phosphor::logging::log<phosphor::logging::level::ERR>(
2628 "Not Find Led Gpio Device!",
2629 phosphor::logging::entry(
2630 "DEVICE=%s",
2631 faultLedPinNames[group + pinGroupOffset][i]
2632 .c_str()));
2633 hasError = true;
2634 continue;
2635 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002636
Zhikui Rence4e73f2019-12-06 13:59:47 -08002637 bool activeHigh =
2638 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2639 try
2640 {
2641 line.request(
2642 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2643 activeHigh
2644 ? 0
2645 : gpiod::line_request::FLAG_ACTIVE_LOW});
2646 line.set_value(ledStateBits[i + group * groupSize]);
2647 }
2648 catch (std::system_error&)
2649 {
2650 phosphor::logging::log<phosphor::logging::level::ERR>(
2651 "Error write Led Gpio Device!",
2652 phosphor::logging::entry(
2653 "DEVICE=%s",
2654 faultLedPinNames[group + pinGroupOffset][i]
2655 .c_str()));
2656 hasError = true;
2657 continue;
2658 }
2659 } // for int i
2660 }
2661 if (hasError)
2662 {
2663 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002664 }
2665 break;
2666 }
2667 default:
2668 {
2669 // now only support two fault types
2670 return ipmi::responseParmOutOfRange();
2671 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002672 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002673 return ipmi::responseSuccess();
2674}
2675
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302676ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2677{
2678 uint8_t prodId = 0;
2679 try
2680 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002681 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302682 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002683 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302684 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2685 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002686 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302687 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2688 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302689 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2690 }
2691 catch (std::exception& e)
2692 {
2693 phosphor::logging::log<phosphor::logging::level::ERR>(
2694 "ipmiOEMReadBoardProductId: Product ID read failed!",
2695 phosphor::logging::entry("ERR=%s", e.what()));
2696 }
2697 return ipmi::responseSuccess(prodId);
2698}
2699
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302700/** @brief implements the get security mode command
2701 * @param ctx - ctx pointer
2702 *
2703 * @returns IPMI completion code with following data
2704 * - restriction mode value - As specified in
2705 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2706 * - special mode value - As specified in
2707 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2708 */
2709ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2710{
2711 namespace securityNameSpace =
2712 sdbusplus::xyz::openbmc_project::Control::Security::server;
2713 uint8_t restrictionModeValue = 0;
2714 uint8_t specialModeValue = 0;
2715
2716 boost::system::error_code ec;
2717 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002718 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302719 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2720 restricionModeProperty);
2721 if (ec)
2722 {
2723 phosphor::logging::log<phosphor::logging::level::ERR>(
2724 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2725 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2726 return ipmi::responseUnspecifiedError();
2727 }
2728 restrictionModeValue = static_cast<uint8_t>(
2729 securityNameSpace::RestrictionMode::convertModesFromString(
2730 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302731 auto varSpecialMode =
2732 ctx->bus->yield_method_call<std::variant<std::string>>(
2733 ctx->yield, ec, specialModeService, specialModeBasePath,
2734 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2735 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302736 if (ec)
2737 {
2738 phosphor::logging::log<phosphor::logging::level::ERR>(
2739 "ipmiGetSecurityMode: failed to get SpecialMode property",
2740 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2741 // fall through, let us not worry about SpecialMode property, which is
2742 // not required in user scenario
2743 }
2744 else
2745 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302746 specialModeValue = static_cast<uint8_t>(
2747 securityNameSpace::SpecialMode::convertModesFromString(
2748 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302749 }
2750 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2751}
2752
2753/** @brief implements the set security mode command
2754 * Command allows to upgrade the restriction mode and won't allow
2755 * to downgrade from system interface
2756 * @param ctx - ctx pointer
2757 * @param restrictionMode - restriction mode value to be set.
2758 *
2759 * @returns IPMI completion code
2760 */
2761ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302762 uint8_t restrictionMode,
2763 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302764{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302765#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2766 if (specialMode)
2767 {
2768 return ipmi::responseReqDataLenInvalid();
2769 }
2770#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302771 namespace securityNameSpace =
2772 sdbusplus::xyz::openbmc_project::Control::Security::server;
2773
2774 ChannelInfo chInfo;
2775 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2776 {
2777 phosphor::logging::log<phosphor::logging::level::ERR>(
2778 "ipmiSetSecurityMode: Failed to get Channel Info",
2779 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2780 return ipmi::responseUnspecifiedError();
2781 }
2782 auto reqMode =
2783 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2784
2785 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2786 (reqMode >
2787 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2788 {
2789 return ipmi::responseInvalidFieldRequest();
2790 }
2791
2792 boost::system::error_code ec;
2793 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002794 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302795 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2796 restricionModeProperty);
2797 if (ec)
2798 {
2799 phosphor::logging::log<phosphor::logging::level::ERR>(
2800 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2801 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2802 return ipmi::responseUnspecifiedError();
2803 }
2804 auto currentRestrictionMode =
2805 securityNameSpace::RestrictionMode::convertModesFromString(
2806 std::get<std::string>(varRestrMode));
2807
2808 if (chInfo.mediumType !=
2809 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2810 currentRestrictionMode > reqMode)
2811 {
2812 phosphor::logging::log<phosphor::logging::level::ERR>(
2813 "ipmiSetSecurityMode - Downgrading security mode not supported "
2814 "through system interface",
2815 phosphor::logging::entry(
2816 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2817 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2818 return ipmi::responseCommandNotAvailable();
2819 }
2820
2821 ec.clear();
2822 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002823 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302824 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2825 restricionModeProperty,
2826 static_cast<std::variant<std::string>>(
2827 securityNameSpace::convertForMessage(reqMode)));
2828
2829 if (ec)
2830 {
2831 phosphor::logging::log<phosphor::logging::level::ERR>(
2832 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2833 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2834 return ipmi::responseUnspecifiedError();
2835 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302836
2837#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2838 if (specialMode)
2839 {
2840 ec.clear();
2841 ctx->bus->yield_method_call<>(
2842 ctx->yield, ec, specialModeService, specialModeBasePath,
2843 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2844 specialModeProperty,
2845 static_cast<std::variant<std::string>>(
2846 securityNameSpace::convertForMessage(
2847 static_cast<securityNameSpace::SpecialMode::Modes>(
2848 specialMode.value()))));
2849
2850 if (ec)
2851 {
2852 phosphor::logging::log<phosphor::logging::level::ERR>(
2853 "ipmiSetSecurityMode: failed to set SpecialMode property",
2854 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2855 return ipmi::responseUnspecifiedError();
2856 }
2857 }
2858#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302859 return ipmi::responseSuccess();
2860}
2861
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002862ipmi::RspType<uint8_t /* restore status */>
2863 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2864{
2865 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2866
2867 if (clr != expClr)
2868 {
2869 return ipmi::responseInvalidFieldRequest();
2870 }
2871 constexpr uint8_t cmdStatus = 0;
2872 constexpr uint8_t cmdDefaultRestore = 0xaa;
2873 constexpr uint8_t cmdFullRestore = 0xbb;
2874 constexpr uint8_t cmdFormat = 0xcc;
2875
2876 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2877
2878 switch (cmd)
2879 {
2880 case cmdStatus:
2881 break;
2882 case cmdDefaultRestore:
2883 case cmdFullRestore:
2884 case cmdFormat:
2885 {
2886 // write file to rwfs root
2887 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2888 std::ofstream restoreFile(restoreOpFname);
2889 if (!restoreFile)
2890 {
2891 return ipmi::responseUnspecifiedError();
2892 }
2893 restoreFile << value << "\n";
2894 break;
2895 }
2896 default:
2897 return ipmi::responseInvalidFieldRequest();
2898 }
2899
2900 constexpr uint8_t restorePending = 0;
2901 constexpr uint8_t restoreComplete = 1;
2902
2903 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2904 ? restorePending
2905 : restoreComplete;
2906 return ipmi::responseSuccess(restoreStatus);
2907}
2908
Chen Yugang39736d52019-07-12 16:24:33 +08002909ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2910{
2911 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002912 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002913
2914 try
2915 {
2916 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2917 std::string service =
2918 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2919 Value variant =
2920 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2921 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2922
2923 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2924 std::get<std::string>(variant)))
2925 {
2926 case nmi::NMISource::BMCSourceSignal::None:
2927 bmcSource = static_cast<uint8_t>(NmiSource::none);
2928 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002929 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2930 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002931 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002932 case nmi::NMISource::BMCSourceSignal::Watchdog:
2933 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002934 break;
2935 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2936 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2937 break;
2938 case nmi::NMISource::BMCSourceSignal::MemoryError:
2939 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2940 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002941 case nmi::NMISource::BMCSourceSignal::PciBusError:
2942 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002943 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002944 case nmi::NMISource::BMCSourceSignal::PCH:
2945 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002946 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002947 case nmi::NMISource::BMCSourceSignal::Chipset:
2948 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002949 break;
2950 default:
2951 phosphor::logging::log<phosphor::logging::level::ERR>(
2952 "NMI source: invalid property!",
2953 phosphor::logging::entry(
2954 "PROP=%s", std::get<std::string>(variant).c_str()));
2955 return ipmi::responseResponseError();
2956 }
2957 }
2958 catch (sdbusplus::exception::SdBusError& e)
2959 {
2960 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2961 return ipmi::responseResponseError();
2962 }
2963
2964 return ipmi::responseSuccess(bmcSource);
2965}
2966
2967ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2968{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002969 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002970
2971 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2972 nmi::NMISource::BMCSourceSignal::None;
2973
2974 switch (NmiSource(sourceId))
2975 {
2976 case NmiSource::none:
2977 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2978 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002979 case NmiSource::frontPanelButton:
2980 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08002981 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002982 case NmiSource::watchdog:
2983 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08002984 break;
2985 case NmiSource::chassisCmd:
2986 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2987 break;
2988 case NmiSource::memoryError:
2989 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2990 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002991 case NmiSource::pciBusError:
2992 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08002993 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002994 case NmiSource::pch:
2995 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08002996 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002997 case NmiSource::chipset:
2998 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08002999 break;
3000 default:
3001 phosphor::logging::log<phosphor::logging::level::ERR>(
3002 "NMI source: invalid property!");
3003 return ipmi::responseResponseError();
3004 }
3005
3006 try
3007 {
3008 // keep NMI signal source
3009 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3010 std::string service =
3011 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003012 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3013 oemNmiBmcSourceObjPathProp,
3014 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003015 // set Enabled property to inform NMI source handling
3016 // to trigger a NMI_OUT BSOD.
3017 // if it's triggered by NMI source property changed,
3018 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3019 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3020 {
3021 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3022 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3023 static_cast<bool>(true));
3024 }
Chen Yugang39736d52019-07-12 16:24:33 +08003025 }
3026 catch (sdbusplus::exception_t& e)
3027 {
3028 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3029 return ipmi::responseResponseError();
3030 }
3031
3032 return ipmi::responseSuccess();
3033}
3034
James Feist63efafa2019-07-24 12:39:21 -07003035namespace dimmOffset
3036{
3037constexpr const char* dimmPower = "DimmPower";
3038constexpr const char* staticCltt = "StaticCltt";
3039constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3040constexpr const char* offsetInterface =
3041 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3042constexpr const char* property = "DimmOffset";
3043
3044}; // namespace dimmOffset
3045
3046ipmi::RspType<>
3047 ipmiOEMSetDimmOffset(uint8_t type,
3048 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3049{
3050 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3051 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3052 {
3053 return ipmi::responseInvalidFieldRequest();
3054 }
3055
3056 if (data.empty())
3057 {
3058 return ipmi::responseInvalidFieldRequest();
3059 }
3060 nlohmann::json json;
3061
3062 std::ifstream jsonStream(dimmOffsetFile);
3063 if (jsonStream.good())
3064 {
3065 json = nlohmann::json::parse(jsonStream, nullptr, false);
3066 if (json.is_discarded())
3067 {
3068 json = nlohmann::json();
3069 }
3070 jsonStream.close();
3071 }
3072
3073 std::string typeName;
3074 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3075 {
3076 typeName = dimmOffset::dimmPower;
3077 }
3078 else
3079 {
3080 typeName = dimmOffset::staticCltt;
3081 }
3082
3083 nlohmann::json& field = json[typeName];
3084
3085 for (const auto& [index, value] : data)
3086 {
3087 field[index] = value;
3088 }
3089
3090 for (nlohmann::json& val : field)
3091 {
3092 if (val == nullptr)
3093 {
3094 val = static_cast<uint8_t>(0);
3095 }
3096 }
3097
3098 std::ofstream output(dimmOffsetFile);
3099 if (!output.good())
3100 {
3101 std::cerr << "Error writing json file\n";
3102 return ipmi::responseResponseError();
3103 }
3104
3105 output << json.dump(4);
3106
3107 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3108 {
3109 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3110
3111 std::variant<std::vector<uint8_t>> offsets =
3112 field.get<std::vector<uint8_t>>();
3113 auto call = bus->new_method_call(
3114 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3115 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3116 try
3117 {
3118 bus->call(call);
3119 }
3120 catch (sdbusplus::exception_t& e)
3121 {
3122 phosphor::logging::log<phosphor::logging::level::ERR>(
3123 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3124 phosphor::logging::entry("ERR=%s", e.what()));
3125 return ipmi::responseResponseError();
3126 }
3127 }
3128
3129 return ipmi::responseSuccess();
3130}
3131
3132ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3133{
3134
3135 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3136 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3137 {
3138 return ipmi::responseInvalidFieldRequest();
3139 }
3140
3141 std::ifstream jsonStream(dimmOffsetFile);
3142
3143 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3144 if (json.is_discarded())
3145 {
3146 std::cerr << "File error in " << dimmOffsetFile << "\n";
3147 return ipmi::responseResponseError();
3148 }
3149
3150 std::string typeName;
3151 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3152 {
3153 typeName = dimmOffset::dimmPower;
3154 }
3155 else
3156 {
3157 typeName = dimmOffset::staticCltt;
3158 }
3159
3160 auto it = json.find(typeName);
3161 if (it == json.end())
3162 {
3163 return ipmi::responseInvalidFieldRequest();
3164 }
3165
3166 if (it->size() <= index)
3167 {
3168 return ipmi::responseInvalidFieldRequest();
3169 }
3170
3171 uint8_t resp = it->at(index).get<uint8_t>();
3172 return ipmi::responseSuccess(resp);
3173}
3174
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003175namespace boot_options
3176{
3177
3178using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3179using IpmiValue = uint8_t;
3180constexpr auto ipmiDefault = 0;
3181
3182std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3183 {0x01, Source::Sources::Network},
3184 {0x02, Source::Sources::Disk},
3185 {0x05, Source::Sources::ExternalMedia},
3186 {0x0f, Source::Sources::RemovableMedia},
3187 {ipmiDefault, Source::Sources::Default}};
3188
3189std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003190 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003191
3192std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3193 {Source::Sources::Network, 0x01},
3194 {Source::Sources::Disk, 0x02},
3195 {Source::Sources::ExternalMedia, 0x05},
3196 {Source::Sources::RemovableMedia, 0x0f},
3197 {Source::Sources::Default, ipmiDefault}};
3198
3199std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003200 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003201
3202static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3203static constexpr auto bootSourceIntf =
3204 "xyz.openbmc_project.Control.Boot.Source";
3205static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3206static constexpr auto persistentObjPath =
3207 "/xyz/openbmc_project/control/host0/boot";
3208static constexpr auto oneTimePath =
3209 "/xyz/openbmc_project/control/host0/boot/one_time";
3210static constexpr auto bootSourceProp = "BootSource";
3211static constexpr auto bootModeProp = "BootMode";
3212static constexpr auto oneTimeBootEnableProp = "Enabled";
3213static constexpr auto httpBootMode =
3214 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3215
3216enum class BootOptionParameter : size_t
3217{
3218 setInProgress = 0x0,
3219 bootFlags = 0x5,
3220};
3221static constexpr uint8_t setComplete = 0x0;
3222static constexpr uint8_t setInProgress = 0x1;
3223static uint8_t transferStatus = setComplete;
3224static constexpr uint8_t setParmVersion = 0x01;
3225static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3226static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3227static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3228static constexpr uint8_t httpBoot = 0xd;
3229static constexpr uint8_t bootSourceMask = 0x3c;
3230
3231} // namespace boot_options
3232
3233ipmi::RspType<uint8_t, // version
3234 uint8_t, // param
3235 uint8_t, // data0, dependent on parameter
3236 std::optional<uint8_t> // data1, dependent on parameter
3237 >
3238 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3239{
3240 using namespace boot_options;
3241 uint8_t bootOption = 0;
3242
3243 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3244 {
3245 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3246 std::nullopt);
3247 }
3248
3249 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3250 {
3251 phosphor::logging::log<phosphor::logging::level::ERR>(
3252 "Unsupported parameter");
3253 return ipmi::responseResponseError();
3254 }
3255
3256 try
3257 {
3258 auto oneTimeEnabled = false;
3259 // read one time Enabled property
3260 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3261 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3262 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3263 enabledIntf, oneTimeBootEnableProp);
3264 oneTimeEnabled = std::get<bool>(variant);
3265
3266 // get BootSource and BootMode properties
3267 // according to oneTimeEnable
3268 auto bootObjPath = oneTimePath;
3269 if (oneTimeEnabled == false)
3270 {
3271 bootObjPath = persistentObjPath;
3272 }
3273
3274 service = getService(*dbus, bootModeIntf, bootObjPath);
3275 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3276 bootModeProp);
3277
3278 auto bootMode =
3279 Mode::convertModesFromString(std::get<std::string>(variant));
3280
3281 service = getService(*dbus, bootSourceIntf, bootObjPath);
3282 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3283 bootSourceProp);
3284
3285 if (std::get<std::string>(variant) == httpBootMode)
3286 {
3287 bootOption = httpBoot;
3288 }
3289 else
3290 {
3291 auto bootSource = Source::convertSourcesFromString(
3292 std::get<std::string>(variant));
3293 bootOption = sourceDbusToIpmi.at(bootSource);
3294 if (Source::Sources::Default == bootSource)
3295 {
3296 bootOption = modeDbusToIpmi.at(bootMode);
3297 }
3298 }
3299
3300 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3301 : setParmBootFlagsValidPermanent;
3302 bootOption <<= 2; // shift for responseconstexpr
3303 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3304 bootOption);
3305 }
3306 catch (sdbusplus::exception_t& e)
3307 {
3308 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3309 return ipmi::responseResponseError();
3310 }
3311}
3312
3313ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3314 std::optional<uint8_t> bootOption)
3315{
3316 using namespace boot_options;
3317 auto oneTimeEnabled = false;
3318
3319 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3320 {
3321 if (bootOption)
3322 {
3323 return ipmi::responseReqDataLenInvalid();
3324 }
3325
3326 if (transferStatus == setInProgress)
3327 {
3328 phosphor::logging::log<phosphor::logging::level::ERR>(
3329 "boot option set in progress!");
3330 return ipmi::responseResponseError();
3331 }
3332
3333 transferStatus = bootParam;
3334 return ipmi::responseSuccess();
3335 }
3336
3337 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3338 {
3339 phosphor::logging::log<phosphor::logging::level::ERR>(
3340 "Unsupported parameter");
3341 return ipmi::responseResponseError();
3342 }
3343
3344 if (!bootOption)
3345 {
3346 return ipmi::responseReqDataLenInvalid();
3347 }
3348
3349 if (((bootOption.value() & bootSourceMask) >> 2) !=
3350 httpBoot) // not http boot, exit
3351 {
3352 phosphor::logging::log<phosphor::logging::level::ERR>(
3353 "wrong boot option parameter!");
3354 return ipmi::responseParmOutOfRange();
3355 }
3356
3357 try
3358 {
3359 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3360 setParmBootFlagsPermanent;
3361
3362 // read one time Enabled property
3363 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3364 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3365 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3366 enabledIntf, oneTimeBootEnableProp);
3367 oneTimeEnabled = std::get<bool>(variant);
3368
3369 /*
3370 * Check if the current boot setting is onetime or permanent, if the
3371 * request in the command is otherwise, then set the "Enabled"
3372 * property in one_time object path to 'True' to indicate onetime
3373 * and 'False' to indicate permanent.
3374 *
3375 * Once the onetime/permanent setting is applied, then the bootMode
3376 * and bootSource is updated for the corresponding object.
3377 */
3378 if (permanent == oneTimeEnabled)
3379 {
3380 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3381 oneTimeBootEnableProp, !permanent);
3382 }
3383
3384 // set BootSource and BootMode properties
3385 // according to oneTimeEnable or persistent
3386 auto bootObjPath = oneTimePath;
3387 if (oneTimeEnabled == false)
3388 {
3389 bootObjPath = persistentObjPath;
3390 }
3391 std::string bootMode =
3392 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3393 std::string bootSource = httpBootMode;
3394
3395 service = getService(*dbus, bootModeIntf, bootObjPath);
3396 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3397 bootMode);
3398
3399 service = getService(*dbus, bootSourceIntf, bootObjPath);
3400 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3401 bootSourceProp, bootSource);
3402 }
3403 catch (sdbusplus::exception_t& e)
3404 {
3405 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3406 return ipmi::responseResponseError();
3407 }
3408
3409 return ipmi::responseSuccess();
3410}
3411
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003412using BasicVariantType =
3413 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3414 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3415 uint16_t, uint8_t, bool>;
3416using PropertyMapType =
3417 boost::container::flat_map<std::string, BasicVariantType>;
3418static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3419 "xyz.openbmc_project.Configuration.PSUPresence"};
3420int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3421 std::vector<uint64_t>& addrTable)
3422{
3423 boost::system::error_code ec;
3424 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3425 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3426 "/xyz/openbmc_project/object_mapper",
3427 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3428 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3429 if (ec)
3430 {
3431 phosphor::logging::log<phosphor::logging::level::ERR>(
3432 "Failed to set dbus property to cold redundancy");
3433 return -1;
3434 }
3435 for (const auto& object : subtree)
3436 {
3437 std::string pathName = object.first;
3438 for (const auto& serviceIface : object.second)
3439 {
3440 std::string serviceName = serviceIface.first;
3441
3442 ec.clear();
3443 PropertyMapType propMap =
3444 ctx->bus->yield_method_call<PropertyMapType>(
3445 ctx->yield, ec, serviceName, pathName,
3446 "org.freedesktop.DBus.Properties", "GetAll",
3447 "xyz.openbmc_project.Configuration.PSUPresence");
3448 if (ec)
3449 {
3450 phosphor::logging::log<phosphor::logging::level::ERR>(
3451 "Failed to set dbus property to cold redundancy");
3452 return -1;
3453 }
3454 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3455 auto psuAddress =
3456 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3457
3458 if (psuBus == nullptr || psuAddress == nullptr)
3459 {
3460 std::cerr << "error finding necessary "
3461 "entry in configuration\n";
3462 return -1;
3463 }
3464 bus = static_cast<uint8_t>(*psuBus);
3465 addrTable = *psuAddress;
3466 return 0;
3467 }
3468 }
3469 return -1;
3470}
3471
3472static const constexpr uint8_t addrOffset = 8;
3473static const constexpr uint8_t psuRevision = 0xd9;
3474static const constexpr uint8_t defaultPSUBus = 7;
3475// Second Minor, Primary Minor, Major
3476static const constexpr size_t verLen = 3;
3477ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3478{
3479 uint8_t bus = defaultPSUBus;
3480 std::vector<uint64_t> addrTable;
3481 std::vector<uint8_t> result;
3482 if (getPSUAddress(ctx, bus, addrTable))
3483 {
3484 std::cerr << "Failed to get PSU bus and address\n";
3485 return ipmi::responseResponseError();
3486 }
3487
3488 for (const auto& slaveAddr : addrTable)
3489 {
3490 std::vector<uint8_t> writeData = {psuRevision};
3491 std::vector<uint8_t> readBuf(verLen);
3492 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3493 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3494
3495 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3496 if (retI2C != ipmi::ccSuccess)
3497 {
3498 for (size_t idx = 0; idx < verLen; idx++)
3499 {
3500 result.emplace_back(0x00);
3501 }
3502 }
3503 else
3504 {
3505 for (const uint8_t& data : readBuf)
3506 {
3507 result.emplace_back(data);
3508 }
3509 }
3510 }
3511
3512 return ipmi::responseSuccess(result);
3513}
3514
AppaRao Puli28972062019-11-11 02:04:45 +05303515/** @brief implements the maximum size of
3516 * bridgeable messages used between KCS and
3517 * IPMB interfacesget security mode command.
3518 *
3519 * @returns IPMI completion code with following data
3520 * - KCS Buffer Size (In multiples of four bytes)
3521 * - IPMB Buffer Size (In multiples of four bytes)
3522 **/
3523ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3524{
3525 // for now this is hard coded; really this number is dependent on
3526 // the BMC kcs driver as well as the host kcs driver....
3527 // we can't know the latter.
3528 uint8_t kcsMaxBufferSize = 63 / 4;
3529 uint8_t ipmbMaxBufferSize = 128 / 4;
3530
3531 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3532}
3533
Jason M. Bills64796042018-10-03 16:51:55 -07003534static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003535{
3536 phosphor::logging::log<phosphor::logging::level::INFO>(
3537 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003538 ipmiPrintAndRegister(intel::netFnGeneral,
3539 intel::general::cmdGetChassisIdentifier, NULL,
3540 ipmiOEMGetChassisIdentifier,
3541 PRIVILEGE_USER); // get chassis identifier
3542
3543 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3544 NULL, ipmiOEMSetSystemGUID,
3545 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003546
3547 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003548 registerHandler(prioOemBase, intel::netFnGeneral,
3549 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3550 ipmiOEMDisableBMCSystemReset);
3551
Jason M. Billsb02bf092019-08-15 13:01:56 -07003552 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003553 registerHandler(prioOemBase, intel::netFnGeneral,
3554 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3555 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003556
Vernon Mauery98bbf692019-09-16 11:14:59 -07003557 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3558 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003559
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003560 registerHandler(prioOemBase, intel::netFnGeneral,
3561 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3562 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003563
Vernon Mauery98bbf692019-09-16 11:14:59 -07003564 ipmiPrintAndRegister(intel::netFnGeneral,
3565 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3566 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303567
Vernon Mauery98bbf692019-09-16 11:14:59 -07003568 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3569 intel::general::cmdSendEmbeddedFWUpdStatus,
3570 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303571
Vernon Mauery98bbf692019-09-16 11:14:59 -07003572 ipmiPrintAndRegister(intel::netFnGeneral,
3573 intel::general::cmdSetPowerRestoreDelay, NULL,
3574 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3575
3576 ipmiPrintAndRegister(intel::netFnGeneral,
3577 intel::general::cmdGetPowerRestoreDelay, NULL,
3578 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3579
3580 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3581 intel::general::cmdSetOEMUser2Activation,
3582 Privilege::Callback, ipmiOEMSetUser2Activation);
3583
3584 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3585 intel::general::cmdSetSpecialUserPassword,
3586 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303587
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003588 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003589 registerHandler(prioOemBase, intel::netFnGeneral,
3590 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3591 ipmiOEMGetProcessorErrConfig);
3592
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003593 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003594 registerHandler(prioOemBase, intel::netFnGeneral,
3595 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3596 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003597
Vernon Mauery98bbf692019-09-16 11:14:59 -07003598 ipmiPrintAndRegister(intel::netFnGeneral,
3599 intel::general::cmdSetShutdownPolicy, NULL,
3600 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003601
Vernon Mauery98bbf692019-09-16 11:14:59 -07003602 ipmiPrintAndRegister(intel::netFnGeneral,
3603 intel::general::cmdGetShutdownPolicy, NULL,
3604 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003605
anil kumar appanaf945eee2019-09-25 23:29:11 +00003606 registerHandler(prioOemBase, intel::netFnGeneral,
3607 intel::general::cmdSetFanConfig, Privilege::User,
3608 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003609
Vernon Mauery98bbf692019-09-16 11:14:59 -07003610 registerHandler(prioOemBase, intel::netFnGeneral,
3611 intel::general::cmdGetFanConfig, Privilege::User,
3612 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003613
Vernon Mauery98bbf692019-09-16 11:14:59 -07003614 registerHandler(prioOemBase, intel::netFnGeneral,
3615 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3616 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003617
Vernon Mauery98bbf692019-09-16 11:14:59 -07003618 registerHandler(prioOemBase, intel::netFnGeneral,
3619 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3620 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003621
Vernon Mauery98bbf692019-09-16 11:14:59 -07003622 registerHandler(prioOemBase, intel::netFnGeneral,
3623 intel::general::cmdSetFscParameter, Privilege::User,
3624 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003625
Vernon Mauery98bbf692019-09-16 11:14:59 -07003626 registerHandler(prioOemBase, intel::netFnGeneral,
3627 intel::general::cmdGetFscParameter, Privilege::User,
3628 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303629
Vernon Mauery98bbf692019-09-16 11:14:59 -07003630 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3631 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3632 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003633
Vernon Mauery98bbf692019-09-16 11:14:59 -07003634 registerHandler(prioOemBase, intel::netFnGeneral,
3635 intel::general::cmdGetNmiStatus, Privilege::User,
3636 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003637
Vernon Mauery98bbf692019-09-16 11:14:59 -07003638 registerHandler(prioOemBase, intel::netFnGeneral,
3639 intel::general::cmdSetNmiStatus, Privilege::Operator,
3640 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003641
Vernon Mauery98bbf692019-09-16 11:14:59 -07003642 registerHandler(prioOemBase, intel::netFnGeneral,
3643 intel::general::cmdGetEfiBootOptions, Privilege::User,
3644 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003645
Vernon Mauery98bbf692019-09-16 11:14:59 -07003646 registerHandler(prioOemBase, intel::netFnGeneral,
3647 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3648 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303649
Vernon Mauery98bbf692019-09-16 11:14:59 -07003650 registerHandler(prioOemBase, intel::netFnGeneral,
3651 intel::general::cmdGetSecurityMode, Privilege::User,
3652 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303653
Vernon Mauery98bbf692019-09-16 11:14:59 -07003654 registerHandler(prioOemBase, intel::netFnGeneral,
3655 intel::general::cmdSetSecurityMode, Privilege::Admin,
3656 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003657
Vernon Mauery98bbf692019-09-16 11:14:59 -07003658 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3659 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003660
Vernon Mauery98bbf692019-09-16 11:14:59 -07003661 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3662 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3663 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3664
3665 registerHandler(prioOemBase, intel::netFnGeneral,
3666 intel::general::cmdSetFaultIndication, Privilege::Operator,
3667 ipmiOEMSetFaultIndication);
3668
3669 registerHandler(prioOemBase, intel::netFnGeneral,
3670 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3671 ipmiOEMSetCRConfig);
3672
3673 registerHandler(prioOemBase, intel::netFnGeneral,
3674 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3675 ipmiOEMGetCRConfig);
3676
3677 registerHandler(prioOemBase, intel::netFnGeneral,
3678 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003679 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003680
Vernon Mauery98bbf692019-09-16 11:14:59 -07003681 registerHandler(prioOemBase, intel::netFnGeneral,
3682 intel::general::cmdSetDimmOffset, Privilege::Operator,
3683 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003684
Vernon Mauery98bbf692019-09-16 11:14:59 -07003685 registerHandler(prioOemBase, intel::netFnGeneral,
3686 intel::general::cmdGetDimmOffset, Privilege::Operator,
3687 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003688
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003689 registerHandler(prioOemBase, intel::netFnGeneral,
3690 intel::general::cmdGetPSUVersion, Privilege::User,
3691 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303692
3693 registerHandler(prioOemBase, intel::netFnGeneral,
3694 intel::general::cmdGetBufferSize, Privilege::User,
3695 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003696}
3697
3698} // namespace ipmi