blob: a5dea035aa5ff4c7c9cf6c59bf6015e59aea8135 [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 +0800161ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
162 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700163 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800164{
Jason M. Bills64796042018-10-03 16:51:55 -0700165 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800166 // Status code.
167 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700168 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800169 return rc;
170}
171
172// Returns the Chassis Identifier (serial #)
173ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
174 ipmi_request_t request,
175 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700176 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 ipmi_context_t context)
178{
179 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700180 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800181 {
Jason M. Bills64796042018-10-03 16:51:55 -0700182 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800183 return IPMI_CC_REQ_DATA_LEN_INVALID;
184 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700185 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
186 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800187 {
Jason M. Bills64796042018-10-03 16:51:55 -0700188 *dataLen = serial.size(); // length will never exceed response length
189 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800190 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700191 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192 return IPMI_CC_OK;
193 }
Jason M. Bills64796042018-10-03 16:51:55 -0700194 *dataLen = 0;
195 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800196}
197
198ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
199 ipmi_request_t request,
200 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700201 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800202{
203 static constexpr size_t safeBufferLength = 50;
204 char buf[safeBufferLength] = {0};
205 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
206
Jason M. Bills64796042018-10-03 16:51:55 -0700207 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800208 {
Jason M. Bills64796042018-10-03 16:51:55 -0700209 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800210 return IPMI_CC_REQ_DATA_LEN_INVALID;
211 }
212
Jason M. Bills64796042018-10-03 16:51:55 -0700213 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800214
215 snprintf(
216 buf, safeBufferLength,
217 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
218 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
219 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
220 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
221 Data->node3, Data->node2, Data->node1);
222 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
223 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800224
225 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
226 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700227 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
228 std::string service = getService(*dbus, intf, objpath);
229 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800230 return IPMI_CC_OK;
231}
232
Jason M. Billsb02bf092019-08-15 13:01:56 -0700233ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
234 uint7_t reserved1)
235{
236 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
237
238 try
239 {
240 auto service =
241 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
242 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
243 bmcResetDisablesIntf, "ResetOnSMI",
244 !disableResetOnSMI);
245 }
246 catch (std::exception& e)
247 {
248 phosphor::logging::log<phosphor::logging::level::ERR>(
249 "Failed to set BMC reset disables",
250 phosphor::logging::entry("EXCEPTION=%s", e.what()));
251 return ipmi::responseUnspecifiedError();
252 }
253
254 return ipmi::responseSuccess();
255}
256
257ipmi::RspType<bool, // disableResetOnSMI
258 uint7_t // reserved
259 >
260 ipmiOEMGetBMCResetDisables()
261{
262 bool disableResetOnSMI = true;
263
264 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
265 try
266 {
267 auto service =
268 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
269 Value variant =
270 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
271 bmcResetDisablesIntf, "ResetOnSMI");
272 disableResetOnSMI = !std::get<bool>(variant);
273 }
274 catch (std::exception& e)
275 {
276 phosphor::logging::log<phosphor::logging::level::ERR>(
277 "Failed to get BMC reset disables",
278 phosphor::logging::entry("EXCEPTION=%s", e.what()));
279 return ipmi::responseUnspecifiedError();
280 }
281
282 return ipmi::responseSuccess(disableResetOnSMI, 0);
283}
284
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800285ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
286 ipmi_request_t request, ipmi_response_t response,
287 ipmi_data_len_t dataLen, ipmi_context_t context)
288{
289 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
290
Jason M. Bills64796042018-10-03 16:51:55 -0700291 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800292 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800293 *dataLen = 0;
294 return IPMI_CC_REQ_DATA_LEN_INVALID;
295 }
Jason M. Bills64796042018-10-03 16:51:55 -0700296 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297
Vernon Mauery15419dd2019-05-24 09:40:30 -0700298 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800299 std::string service = getService(*dbus, biosVersionIntf, biosObjPath);
300 setDbusProperty(*dbus, service, biosObjPath, biosVersionIntf,
301 biosVersionProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800302 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
303 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700304 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800305 *dataLen = 1;
306 return IPMI_CC_OK;
307}
308
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800309bool getSwVerInfo(uint8_t& bmcMajor, uint8_t& bmcMinor, uint8_t& meMajor,
310 uint8_t& meMinor)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800311{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800312 // step 1 : get BMC Major and Minor numbers from its DBUS property
313 std::optional<MetaRevision> rev{};
314 try
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800316 std::string version = getActiveSoftwareVersionInfo();
317 rev = convertIntelVersion(version);
318 }
319 catch (const std::exception& e)
320 {
321 return false;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800322 }
323
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800324 if (rev.has_value())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800325 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800326 MetaRevision revision = rev.value();
327 bmcMajor = revision.major;
328
329 revision.minor = (revision.minor > 99 ? 99 : revision.minor);
330 bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16;
331 }
332
333 // step 2 : get ME Major and Minor numbers from its DBUS property
334 try
335 {
336 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
337 std::string service =
338 getService(*dbus, "xyz.openbmc_project.Software.Version",
339 "/xyz/openbmc_project/me_version");
340 Value variant =
341 getDbusProperty(*dbus, service, "/xyz/openbmc_project/me_version",
342 "xyz.openbmc_project.Software.Version", "Version");
343
344 std::string& meString = std::get<std::string>(variant);
345
346 // get ME major number
347 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
348 constexpr size_t matchedPhosphor = 6;
349 std::smatch results;
350 if (std::regex_match(meString, results, pattern1))
351 {
352 if (results.size() == matchedPhosphor)
353 {
354 meMajor = static_cast<uint8_t>(std::stoi(results[1]));
355 meMinor = static_cast<uint8_t>(std::stoi(results[2]));
356 }
357 }
358 }
359 catch (sdbusplus::exception::SdBusError& e)
360 {
361 return false;
362 }
363 return true;
364}
365
366ipmi::RspType<
367 std::variant<std::string,
368 std::tuple<uint8_t, std::array<uint8_t, 2>,
369 std::array<uint8_t, 2>, std::array<uint8_t, 2>,
370 std::array<uint8_t, 2>, std::array<uint8_t, 2>>,
371 std::tuple<uint8_t, std::array<uint8_t, 2>>>>
372 ipmiOEMGetDeviceInfo(uint8_t entityType, uint8_t countToRead,
373 uint8_t offset)
374{
375 if (countToRead == 0)
376 {
377 return ipmi::responseReqDataLenInvalid();
378 }
379
380 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
381 {
382 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800383 }
384
385 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800386 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800387 {
388 case OEMDevEntityType::biosId:
389 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700390 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800391 std::string service =
392 getService(*dbus, biosVersionIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800393 try
394 {
Yong Li2742b852019-12-16 14:55:11 +0800395 Value variant =
396 getDbusProperty(*dbus, service, biosObjPath,
397 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700398 std::string& idString = std::get<std::string>(variant);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800399 if (offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800400 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800401 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800402 }
Jason M. Bills64796042018-10-03 16:51:55 -0700403 size_t length = 0;
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800404 if (countToRead > (idString.size() - offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700405 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800406 length = idString.size() - offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700407 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800408 else
409 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800410 length = countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800411 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800412
413 std::string readBuf = {0};
414 readBuf.resize(length);
415 std::copy_n(idString.begin() + offset, length,
416 (readBuf.begin()));
417 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800418 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700419 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800420 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800421 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800422 }
423 }
424 break;
425
426 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800427 {
428 constexpr const size_t verLen = 2;
429 constexpr const size_t verTotalLen = 10;
430 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
431 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
432 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
433 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
434 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
435 // data0/1: BMC version number; data6/7: ME version number
436 // the others: HSC0/1/2 version number, not avaible.
437 if (true != getSwVerInfo(bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
438 {
439 return ipmi::responseUnspecifiedError();
440 }
441 return ipmi::responseSuccess(
442 std::tuple<
443 uint8_t, std::array<uint8_t, verLen>,
444 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
445 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
446 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
447 }
448 break;
449
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800450 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800451 {
452 constexpr const size_t sdrLen = 2;
453 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
454 return ipmi::responseSuccess(
455 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
456 readBuf});
457 }
458 break;
459
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800460 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800461 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800462 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800463}
464
465ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
466 ipmi_request_t request, ipmi_response_t response,
467 ipmi_data_len_t dataLen, ipmi_context_t context)
468{
469 if (*dataLen != 0)
470 {
Jason M. Bills64796042018-10-03 16:51:55 -0700471 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800472 return IPMI_CC_REQ_DATA_LEN_INVALID;
473 }
474
475 *dataLen = 1;
476 uint8_t* res = reinterpret_cast<uint8_t*>(response);
477 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
478 // AIC is available so that BIOS will not timeout repeatly which leads to
479 // slow booting.
480 *res = 0; // Byte1=Count of SlotPosition/FruID records.
481 return IPMI_CC_OK;
482}
483
Jason M. Bills64796042018-10-03 16:51:55 -0700484ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
485 ipmi_request_t request,
486 ipmi_response_t response,
487 ipmi_data_len_t dataLen,
488 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800489{
Jason M. Bills64796042018-10-03 16:51:55 -0700490 GetPowerRestoreDelayRes* resp =
491 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
492
493 if (*dataLen != 0)
494 {
495 *dataLen = 0;
496 return IPMI_CC_REQ_DATA_LEN_INVALID;
497 }
498
Vernon Mauery15419dd2019-05-24 09:40:30 -0700499 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700500 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700501 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700502 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700503 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700504 powerRestoreDelayIntf, powerRestoreDelayProp);
505
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700506 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700507 resp->byteLSB = delay;
508 resp->byteMSB = delay >> 8;
509
510 *dataLen = sizeof(GetPowerRestoreDelayRes);
511
512 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800513}
514
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800515static uint8_t bcdToDec(uint8_t val)
516{
517 return ((val / 16 * 10) + (val % 16));
518}
519
520// Allows an update utility or system BIOS to send the status of an embedded
521// firmware update attempt to the BMC. After received, BMC will create a logging
522// record.
523ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
524 uint8_t majorRevision,
525 uint8_t minorRevision,
526 uint32_t auxInfo)
527{
528 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700529 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800530 target = (target & selEvtTargetMask) >> selEvtTargetShift;
531
532 /* make sure the status is 0, 1, or 2 as per the spec */
533 if (status > 2)
534 {
535 return ipmi::response(ipmi::ccInvalidFieldRequest);
536 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700537 /* make sure the target is 0, 1, 2, or 4 as per the spec */
538 if (target > 4 || target == 3)
539 {
540 return ipmi::response(ipmi::ccInvalidFieldRequest);
541 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800542 /*orignal OEM command is to record OEM SEL.
543 But openbmc does not support OEM SEL, so we redirect it to redfish event
544 logging. */
545 std::string buildInfo;
546 std::string action;
547 switch (FWUpdateTarget(target))
548 {
549 case FWUpdateTarget::targetBMC:
550 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700551 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800552 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
553 " BuildID: " + std::to_string(auxInfo);
554 buildInfo += std::to_string(auxInfo);
555 break;
556 case FWUpdateTarget::targetBIOS:
557 firmware = "BIOS";
558 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700559 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800560 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
561 " minor: " +
562 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
563 " ReleaseNumber: " + // ASCII encoded
564 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
565 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
566 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
567 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
568 break;
569 case FWUpdateTarget::targetME:
570 firmware = "ME";
571 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700572 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800573 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
574 " minor2: " +
575 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
576 " build1: " +
577 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
578 " build2: " +
579 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
580 break;
581 case FWUpdateTarget::targetOEMEWS:
582 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700583 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800584 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
585 " BuildID: " + std::to_string(auxInfo);
586 break;
587 }
588
Jason M. Billsdc249272019-04-03 09:58:40 -0700589 static const std::string openBMCMessageRegistryVersion("0.1");
590 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
591
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800592 switch (status)
593 {
594 case 0x0:
595 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700596 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800597 break;
598 case 0x1:
599 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700600 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800601 break;
602 case 0x2:
603 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700604 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800605 break;
606 default:
607 action = "unknown";
608 break;
609 }
610
Jason M. Billsdc249272019-04-03 09:58:40 -0700611 std::string firmwareInstanceStr =
612 firmware + " instance: " + std::to_string(instance);
613 std::string message("[firmware update] " + firmwareInstanceStr +
614 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800615
616 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700617 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
618 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
619 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800620 return ipmi::responseSuccess();
621}
622
Jason M. Bills64796042018-10-03 16:51:55 -0700623ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
624 ipmi_request_t request,
625 ipmi_response_t response,
626 ipmi_data_len_t dataLen,
627 ipmi_context_t context)
628{
629 SetPowerRestoreDelayReq* data =
630 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
631 uint16_t delay = 0;
632
633 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
634 {
635 *dataLen = 0;
636 return IPMI_CC_REQ_DATA_LEN_INVALID;
637 }
638 delay = data->byteMSB;
639 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700640 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700641 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700642 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
643 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700644 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
645 *dataLen = 0;
646
647 return IPMI_CC_OK;
648}
649
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700650static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700651{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700652 static constexpr const char* cpuPresencePathPrefix =
653 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
654 static constexpr const char* cpuPresenceIntf =
655 "xyz.openbmc_project.Inventory.Item";
656 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
657 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
658 try
Jason M. Bills64796042018-10-03 16:51:55 -0700659 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700660 auto service =
661 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
662
663 ipmi::Value result = ipmi::getDbusProperty(
664 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
665 return std::get<bool>(result);
666 }
667 catch (const std::exception& e)
668 {
669 phosphor::logging::log<phosphor::logging::level::INFO>(
670 "Cannot find processor presence",
671 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
672 return false;
673 }
674}
675
676ipmi::RspType<bool, // CATERR Reset Enabled
677 bool, // ERR2 Reset Enabled
678 uint6_t, // reserved
679 uint8_t, // reserved, returns 0x3F
680 uint6_t, // CPU1 CATERR Count
681 uint2_t, // CPU1 Status
682 uint6_t, // CPU2 CATERR Count
683 uint2_t, // CPU2 Status
684 uint6_t, // CPU3 CATERR Count
685 uint2_t, // CPU3 Status
686 uint6_t, // CPU4 CATERR Count
687 uint2_t, // CPU4 Status
688 uint8_t // Crashdump Count
689 >
690 ipmiOEMGetProcessorErrConfig()
691{
692 bool resetOnCATERR = false;
693 bool resetOnERR2 = false;
694 uint6_t cpu1CATERRCount = 0;
695 uint6_t cpu2CATERRCount = 0;
696 uint6_t cpu3CATERRCount = 0;
697 uint6_t cpu4CATERRCount = 0;
698 uint8_t crashdumpCount = 0;
699 uint2_t cpu1Status =
700 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
701 uint2_t cpu2Status =
702 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
703 uint2_t cpu3Status =
704 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
705 uint2_t cpu4Status =
706 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
707
708 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
709 try
710 {
711 auto service = ipmi::getService(*busp, processorErrConfigIntf,
712 processorErrConfigObjPath);
713
714 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
715 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
716 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
717 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
718 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
719 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
720 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
721 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
722 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
723 }
724 catch (const std::exception& e)
725 {
726 phosphor::logging::log<phosphor::logging::level::ERR>(
727 "Failed to fetch processor error config",
728 phosphor::logging::entry("ERROR=%s", e.what()));
729 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700730 }
731
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700732 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
733 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
734 cpu2Status, cpu3CATERRCount, cpu3Status,
735 cpu4CATERRCount, cpu4Status, crashdumpCount);
736}
Jason M. Bills64796042018-10-03 16:51:55 -0700737
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700738ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
739 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
740 std::optional<bool> clearCPUErrorCount,
741 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
742{
743 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700744
745 try
746 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700747 auto service = ipmi::getService(*busp, processorErrConfigIntf,
748 processorErrConfigObjPath);
749 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
750 processorErrConfigIntf, "ResetOnCATERR",
751 resetOnCATERR);
752 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
753 processorErrConfigIntf, "ResetOnERR2",
754 resetOnERR2);
755 if (clearCPUErrorCount.value_or(false))
756 {
757 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700758 processorErrConfigIntf, "ErrorCountCPU1",
759 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700760 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700761 processorErrConfigIntf, "ErrorCountCPU2",
762 static_cast<uint8_t>(0));
763 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
764 processorErrConfigIntf, "ErrorCountCPU3",
765 static_cast<uint8_t>(0));
766 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
767 processorErrConfigIntf, "ErrorCountCPU4",
768 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700769 }
770 if (clearCrashdumpCount.value_or(false))
771 {
772 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700773 processorErrConfigIntf, "CrashdumpCount",
774 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700775 }
Jason M. Bills64796042018-10-03 16:51:55 -0700776 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700777 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700778 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800779 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700780 "Failed to set processor error config",
781 phosphor::logging::entry("EXCEPTION=%s", e.what()));
782 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700783 }
784
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700785 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700786}
787
Yong Li703922d2018-11-06 13:25:31 +0800788ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
789 ipmi_request_t request,
790 ipmi_response_t response,
791 ipmi_data_len_t dataLen,
792 ipmi_context_t context)
793{
794 GetOEMShutdownPolicyRes* resp =
795 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
796
797 if (*dataLen != 0)
798 {
799 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800800 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800801 *dataLen = 0;
802 return IPMI_CC_REQ_DATA_LEN_INVALID;
803 }
804
805 *dataLen = 0;
806
807 try
808 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700809 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800810 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700811 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
812 Value variant = getDbusProperty(
813 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
814 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800815
816 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
817 convertPolicyFromString(std::get<std::string>(variant)) ==
818 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
819 NoShutdownOnOCOT)
820 {
821 resp->policy = 0;
822 }
823 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
824 convertPolicyFromString(std::get<std::string>(variant)) ==
825 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
826 Policy::ShutdownOnOCOT)
827 {
828 resp->policy = 1;
829 }
830 else
831 {
832 phosphor::logging::log<phosphor::logging::level::ERR>(
833 "oem_set_shutdown_policy: invalid property!",
834 phosphor::logging::entry(
835 "PROP=%s", std::get<std::string>(variant).c_str()));
836 return IPMI_CC_UNSPECIFIED_ERROR;
837 }
Yong Li703922d2018-11-06 13:25:31 +0800838 // TODO needs to check if it is multi-node products,
839 // policy is only supported on node 3/4
840 resp->policySupport = shutdownPolicySupported;
841 }
842 catch (sdbusplus::exception_t& e)
843 {
844 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
845 return IPMI_CC_UNSPECIFIED_ERROR;
846 }
847
848 *dataLen = sizeof(GetOEMShutdownPolicyRes);
849 return IPMI_CC_OK;
850}
851
852ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
853 ipmi_request_t request,
854 ipmi_response_t response,
855 ipmi_data_len_t dataLen,
856 ipmi_context_t context)
857{
858 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800859 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
860 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
861 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800862
863 // TODO needs to check if it is multi-node products,
864 // policy is only supported on node 3/4
865 if (*dataLen != 1)
866 {
867 phosphor::logging::log<phosphor::logging::level::ERR>(
868 "oem_set_shutdown_policy: invalid input len!");
869 *dataLen = 0;
870 return IPMI_CC_REQ_DATA_LEN_INVALID;
871 }
872
873 *dataLen = 0;
874 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
875 {
876 phosphor::logging::log<phosphor::logging::level::ERR>(
877 "oem_set_shutdown_policy: invalid input!");
878 return IPMI_CC_INVALID_FIELD_REQUEST;
879 }
880
Yong Li0669d192019-05-06 14:01:46 +0800881 if (*req == noShutdownOnOCOT)
882 {
883 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
884 Policy::NoShutdownOnOCOT;
885 }
886 else
887 {
888 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
889 Policy::ShutdownOnOCOT;
890 }
891
Yong Li703922d2018-11-06 13:25:31 +0800892 try
893 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700894 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800895 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700896 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800897 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700898 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800899 oemShutdownPolicyObjPathProp,
900 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800901 }
902 catch (sdbusplus::exception_t& e)
903 {
904 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
905 return IPMI_CC_UNSPECIFIED_ERROR;
906 }
907
908 return IPMI_CC_OK;
909}
910
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530911/** @brief implementation for check the DHCP or not in IPv4
912 * @param[in] Channel - Channel number
913 * @returns true or false.
914 */
915static bool isDHCPEnabled(uint8_t Channel)
916{
917 try
918 {
919 auto ethdevice = getChannelName(Channel);
920 if (ethdevice.empty())
921 {
922 return false;
923 }
924 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700925 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530926 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700927 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
928 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530929 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700930 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530931 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
932 {
933 return true;
934 }
935 else
936 {
937 return false;
938 }
939 }
940 catch (sdbusplus::exception_t& e)
941 {
942 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
943 return true;
944 }
945}
946
947/** @brief implementes for check the DHCP or not in IPv6
948 * @param[in] Channel - Channel number
949 * @returns true or false.
950 */
951static bool isDHCPIPv6Enabled(uint8_t Channel)
952{
953
954 try
955 {
956 auto ethdevice = getChannelName(Channel);
957 if (ethdevice.empty())
958 {
959 return false;
960 }
961 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700962 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530963 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700964 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
965 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530966 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700967 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530968 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
969 {
970 return true;
971 }
972 else
973 {
974 return false;
975 }
976 }
977 catch (sdbusplus::exception_t& e)
978 {
979 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
980 return true;
981 }
982}
983
984/** @brief implementes the creating of default new user
985 * @param[in] userName - new username in 16 bytes.
986 * @param[in] userPassword - new password in 20 bytes
987 * @returns ipmi completion code.
988 */
989ipmi::RspType<> ipmiOEMSetUser2Activation(
990 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
991 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
992{
993 bool userState = false;
994 // Check for System Interface not exist and LAN should be static
995 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
996 {
997 ChannelInfo chInfo;
998 try
999 {
1000 getChannelInfo(channel, chInfo);
1001 }
1002 catch (sdbusplus::exception_t& e)
1003 {
1004 phosphor::logging::log<phosphor::logging::level::ERR>(
1005 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1006 phosphor::logging::entry("MSG: %s", e.description()));
1007 return ipmi::response(ipmi::ccUnspecifiedError);
1008 }
1009 if (chInfo.mediumType ==
1010 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1011 {
1012 phosphor::logging::log<phosphor::logging::level::ERR>(
1013 "ipmiOEMSetUser2Activation: system interface exist .");
1014 return ipmi::response(ipmi::ccCommandNotAvailable);
1015 }
1016 else
1017 {
1018
1019 if (chInfo.mediumType ==
1020 static_cast<uint8_t>(EChannelMediumType::lan8032))
1021 {
1022 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1023 {
1024 phosphor::logging::log<phosphor::logging::level::ERR>(
1025 "ipmiOEMSetUser2Activation: DHCP enabled .");
1026 return ipmi::response(ipmi::ccCommandNotAvailable);
1027 }
1028 }
1029 }
1030 }
1031 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1032 if (ipmi::ccSuccess ==
1033 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1034 {
1035 if (enabledUsers > 1)
1036 {
1037 phosphor::logging::log<phosphor::logging::level::ERR>(
1038 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1039 return ipmi::response(ipmi::ccCommandNotAvailable);
1040 }
1041 // Check the user 2 is enabled or not
1042 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1043 if (userState == true)
1044 {
1045 phosphor::logging::log<phosphor::logging::level::ERR>(
1046 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1047 return ipmi::response(ipmi::ccCommandNotAvailable);
1048 }
1049 }
1050 else
1051 {
1052 return ipmi::response(ipmi::ccUnspecifiedError);
1053 }
1054
1055#if BYTE_ORDER == LITTLE_ENDIAN
1056 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1057#endif
1058#if BYTE_ORDER == BIG_ENDIAN
1059 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1060#endif
1061
1062 if (ipmi::ccSuccess ==
1063 ipmiUserSetUserName(ipmiDefaultUserId,
1064 reinterpret_cast<const char*>(userName.data())))
1065 {
1066 if (ipmi::ccSuccess ==
1067 ipmiUserSetUserPassword(
1068 ipmiDefaultUserId,
1069 reinterpret_cast<const char*>(userPassword.data())))
1070 {
1071 if (ipmi::ccSuccess ==
1072 ipmiUserSetPrivilegeAccess(
1073 ipmiDefaultUserId,
1074 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1075 privAccess, true))
1076 {
1077 phosphor::logging::log<phosphor::logging::level::INFO>(
1078 "ipmiOEMSetUser2Activation: user created successfully ");
1079 return ipmi::responseSuccess();
1080 }
1081 }
1082 // we need to delete the default user id which added in this command as
1083 // password / priv setting is failed.
1084 ipmiUserSetUserName(ipmiDefaultUserId, "");
1085 phosphor::logging::log<phosphor::logging::level::ERR>(
1086 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1087 }
1088 else
1089 {
1090 phosphor::logging::log<phosphor::logging::level::ERR>(
1091 "ipmiOEMSetUser2Activation: Setting username failed.");
1092 }
1093
1094 return ipmi::response(ipmi::ccCommandNotAvailable);
1095}
1096
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301097/** @brief implementes executing the linux command
1098 * @param[in] linux command
1099 * @returns status
1100 */
1101
1102static uint8_t executeCmd(const char* path)
1103{
1104 boost::process::child execProg(path);
1105 execProg.wait();
1106
1107 int retCode = execProg.exit_code();
1108 if (retCode)
1109 {
1110 return ipmi::ccUnspecifiedError;
1111 }
1112 return ipmi::ccSuccess;
1113}
1114
1115/** @brief implementes ASD Security event logging
1116 * @param[in] Event message string
1117 * @param[in] Event Severity
1118 * @returns status
1119 */
1120
1121static void atScaleDebugEventlog(std::string msg, int severity)
1122{
1123 std::string eventStr = "OpenBMC.0.1." + msg;
1124 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1125 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1126 eventStr.c_str(), NULL);
1127}
1128
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301129/** @brief implementes setting password for special user
1130 * @param[in] specialUserIndex
1131 * @param[in] userPassword - new password in 20 bytes
1132 * @returns ipmi completion code.
1133 */
1134ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1135 uint8_t specialUserIndex,
1136 std::vector<uint8_t> userPassword)
1137{
1138 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301139 ipmi_ret_t status = ipmi::ccSuccess;
1140
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301141 try
1142 {
1143 getChannelInfo(ctx->channel, chInfo);
1144 }
1145 catch (sdbusplus::exception_t& e)
1146 {
1147 phosphor::logging::log<phosphor::logging::level::ERR>(
1148 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1149 phosphor::logging::entry("MSG: %s", e.description()));
1150 return ipmi::responseUnspecifiedError();
1151 }
1152 if (chInfo.mediumType !=
1153 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1154 {
1155 phosphor::logging::log<phosphor::logging::level::ERR>(
1156 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1157 "interface");
1158 return ipmi::responseCommandNotAvailable();
1159 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301160
1161 // 0 for root user and 1 for AtScaleDebug is allowed
1162 if (specialUserIndex >
1163 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301164 {
1165 phosphor::logging::log<phosphor::logging::level::ERR>(
1166 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1167 return ipmi::responseParmOutOfRange();
1168 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301169 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301170 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301171 constexpr uint8_t minPasswordSizeRequired = 6;
1172 std::string passwd;
1173 if (userPassword.size() < minPasswordSizeRequired ||
1174 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1175 {
1176 return ipmi::responseReqDataLenInvalid();
1177 }
1178 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1179 userPassword.size());
1180 if (specialUserIndex ==
1181 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1182 {
1183 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1184
1185 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1186 }
1187 else
1188 {
1189 status = ipmiSetSpecialUserPassword("root", passwd);
1190 }
1191 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301192 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301193 else
1194 {
1195 if (specialUserIndex ==
1196 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1197 {
1198 status = executeCmd("passwd -d root");
1199 }
1200 else
1201 {
1202
1203 status = executeCmd("passwd -d asdbg");
1204
1205 if (status == 0)
1206 {
1207 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1208 LOG_INFO);
1209 }
1210 }
1211 return ipmi::response(status);
1212 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301213}
1214
Kuiying Wang45f04982018-12-26 09:23:08 +08001215namespace ledAction
1216{
1217using namespace sdbusplus::xyz::openbmc_project::Led::server;
1218std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001219 {Physical::Action::Off, 0},
1220 {Physical::Action::On, 2},
1221 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001222
1223std::map<uint8_t, std::string> offsetObjPath = {
1224 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1225
1226} // namespace ledAction
1227
1228int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1229 const std::string& objPath, uint8_t& state)
1230{
1231 try
1232 {
1233 std::string service = getService(bus, intf, objPath);
1234 Value stateValue =
1235 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001236 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001237 state = ledAction::actionDbusToIpmi.at(
1238 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1239 convertActionFromString(strState));
1240 }
1241 catch (sdbusplus::exception::SdBusError& e)
1242 {
1243 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1244 return -1;
1245 }
1246 return 0;
1247}
1248
1249ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1250 ipmi_request_t request, ipmi_response_t response,
1251 ipmi_data_len_t dataLen, ipmi_context_t context)
1252{
1253 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1254 // LED Status
1255 //[1:0] = Reserved
1256 //[3:2] = Status(Amber)
1257 //[5:4] = Status(Green)
1258 //[7:6] = System Identify
1259 // Status definitions:
1260 // 00b = Off
1261 // 01b = Blink
1262 // 10b = On
1263 // 11b = invalid
1264 if (*dataLen != 0)
1265 {
1266 phosphor::logging::log<phosphor::logging::level::ERR>(
1267 "oem_get_led_status: invalid input len!");
1268 *dataLen = 0;
1269 return IPMI_CC_REQ_DATA_LEN_INVALID;
1270 }
1271
1272 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1273 *resp = 0;
1274 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001275 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001276 for (auto it = ledAction::offsetObjPath.begin();
1277 it != ledAction::offsetObjPath.end(); ++it)
1278 {
1279 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001280 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001281 {
1282 phosphor::logging::log<phosphor::logging::level::ERR>(
1283 "oem_get_led_status: fail to get ID LED status!");
1284 return IPMI_CC_UNSPECIFIED_ERROR;
1285 }
1286 *resp |= state << it->first;
1287 }
1288
1289 *dataLen = sizeof(*resp);
1290 return IPMI_CC_OK;
1291}
1292
Yong Li23737fe2019-02-19 08:49:55 +08001293ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1294 ipmi_request_t request,
1295 ipmi_response_t response,
1296 ipmi_data_len_t dataLen,
1297 ipmi_context_t context)
1298{
1299 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1300 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1301
1302 if (*dataLen == 0)
1303 {
1304 phosphor::logging::log<phosphor::logging::level::ERR>(
1305 "CfgHostSerial: invalid input len!",
1306 phosphor::logging::entry("LEN=%d", *dataLen));
1307 return IPMI_CC_REQ_DATA_LEN_INVALID;
1308 }
1309
1310 switch (req->command)
1311 {
1312 case getHostSerialCfgCmd:
1313 {
1314 if (*dataLen != 1)
1315 {
1316 phosphor::logging::log<phosphor::logging::level::ERR>(
1317 "CfgHostSerial: invalid input len!");
1318 *dataLen = 0;
1319 return IPMI_CC_REQ_DATA_LEN_INVALID;
1320 }
1321
1322 *dataLen = 0;
1323
1324 boost::process::ipstream is;
1325 std::vector<std::string> data;
1326 std::string line;
1327 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1328 boost::process::std_out > is);
1329
1330 while (c1.running() && std::getline(is, line) && !line.empty())
1331 {
1332 data.push_back(line);
1333 }
1334
1335 c1.wait();
1336 if (c1.exit_code())
1337 {
1338 phosphor::logging::log<phosphor::logging::level::ERR>(
1339 "CfgHostSerial:: error on execute",
1340 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1341 // Using the default value
1342 *resp = 0;
1343 }
1344 else
1345 {
1346 if (data.size() != 1)
1347 {
1348 phosphor::logging::log<phosphor::logging::level::ERR>(
1349 "CfgHostSerial:: error on read env");
1350 return IPMI_CC_UNSPECIFIED_ERROR;
1351 }
1352 try
1353 {
1354 unsigned long tmp = std::stoul(data[0]);
1355 if (tmp > std::numeric_limits<uint8_t>::max())
1356 {
1357 throw std::out_of_range("Out of range");
1358 }
1359 *resp = static_cast<uint8_t>(tmp);
1360 }
1361 catch (const std::invalid_argument& e)
1362 {
1363 phosphor::logging::log<phosphor::logging::level::ERR>(
1364 "invalid config ",
1365 phosphor::logging::entry("ERR=%s", e.what()));
1366 return IPMI_CC_UNSPECIFIED_ERROR;
1367 }
1368 catch (const std::out_of_range& e)
1369 {
1370 phosphor::logging::log<phosphor::logging::level::ERR>(
1371 "out_of_range config ",
1372 phosphor::logging::entry("ERR=%s", e.what()));
1373 return IPMI_CC_UNSPECIFIED_ERROR;
1374 }
1375 }
1376
1377 *dataLen = 1;
1378 break;
1379 }
1380 case setHostSerialCfgCmd:
1381 {
1382 if (*dataLen != sizeof(CfgHostSerialReq))
1383 {
1384 phosphor::logging::log<phosphor::logging::level::ERR>(
1385 "CfgHostSerial: invalid input len!");
1386 *dataLen = 0;
1387 return IPMI_CC_REQ_DATA_LEN_INVALID;
1388 }
1389
1390 *dataLen = 0;
1391
1392 if (req->parameter > HostSerialCfgParamMax)
1393 {
1394 phosphor::logging::log<phosphor::logging::level::ERR>(
1395 "CfgHostSerial: invalid input!");
1396 return IPMI_CC_INVALID_FIELD_REQUEST;
1397 }
1398
1399 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1400 std::to_string(req->parameter));
1401
1402 c1.wait();
1403 if (c1.exit_code())
1404 {
1405 phosphor::logging::log<phosphor::logging::level::ERR>(
1406 "CfgHostSerial:: error on execute",
1407 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1408 return IPMI_CC_UNSPECIFIED_ERROR;
1409 }
1410 break;
1411 }
1412 default:
1413 phosphor::logging::log<phosphor::logging::level::ERR>(
1414 "CfgHostSerial: invalid input!");
1415 *dataLen = 0;
1416 return IPMI_CC_INVALID_FIELD_REQUEST;
1417 }
1418
1419 return IPMI_CC_OK;
1420}
1421
James Feist91244a62019-02-19 15:04:54 -08001422constexpr const char* thermalModeInterface =
1423 "xyz.openbmc_project.Control.ThermalMode";
1424constexpr const char* thermalModePath =
1425 "/xyz/openbmc_project/control/thermal_mode";
1426
1427bool getFanProfileInterface(
1428 sdbusplus::bus::bus& bus,
1429 boost::container::flat_map<
1430 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1431{
1432 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1433 "GetAll");
1434 call.append(thermalModeInterface);
1435 try
1436 {
1437 auto data = bus.call(call);
1438 data.read(resp);
1439 }
1440 catch (sdbusplus::exception_t& e)
1441 {
1442 phosphor::logging::log<phosphor::logging::level::ERR>(
1443 "getFanProfileInterface: can't get thermal mode!",
1444 phosphor::logging::entry("ERR=%s", e.what()));
1445 return false;
1446 }
1447 return true;
1448}
1449
anil kumar appanaf945eee2019-09-25 23:29:11 +00001450/**@brief implements the OEM set fan config.
1451 * @param selectedFanProfile - fan profile to enable
1452 * @param reserved1
1453 * @param performanceMode - Performance/Acoustic mode
1454 * @param reserved2
1455 * @param setPerformanceMode - set Performance/Acoustic mode
1456 * @param setFanProfile - set fan profile
1457 *
1458 * @return IPMI completion code.
1459 **/
1460ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1461
1462 uint2_t reserved1, bool performanceMode,
1463 uint3_t reserved2, bool setPerformanceMode,
1464 bool setFanProfile)
James Feist91244a62019-02-19 15:04:54 -08001465{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001466 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001467 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001468 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001469 }
James Feist91244a62019-02-19 15:04:54 -08001470 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001471 boost::container::flat_map<
1472 std::string, std::variant<std::vector<std::string>, std::string>>
1473 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001474 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1475 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001476 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001477 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001478 }
1479
1480 std::vector<std::string>* supported =
1481 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1482 if (supported == nullptr)
1483 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001484 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001485 }
1486 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001487 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001488 {
James Feist91244a62019-02-19 15:04:54 -08001489 if (performanceMode)
1490 {
1491
1492 if (std::find(supported->begin(), supported->end(),
1493 "Performance") != supported->end())
1494 {
1495 mode = "Performance";
1496 }
1497 }
1498 else
1499 {
James Feist91244a62019-02-19 15:04:54 -08001500 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1501 supported->end())
1502 {
1503 mode = "Acoustic";
1504 }
1505 }
1506 if (mode.empty())
1507 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001508 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001509 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001510
1511 try
1512 {
1513 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1514 thermalModeInterface, "Current", mode);
1515 }
1516 catch (sdbusplus::exception_t& e)
1517 {
1518 phosphor::logging::log<phosphor::logging::level::ERR>(
1519 "ipmiOEMSetFanConfig: can't set thermal mode!",
1520 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1521 return ipmi::responseResponseError();
1522 }
James Feist91244a62019-02-19 15:04:54 -08001523 }
1524
anil kumar appanaf945eee2019-09-25 23:29:11 +00001525 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001526}
1527
James Feist5b693632019-07-09 09:06:09 -07001528ipmi::RspType<uint8_t, // profile support map
1529 uint8_t, // fan control profile enable
1530 uint8_t, // flags
1531 uint32_t // dimm presence bit map
1532 >
1533 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001534{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301535 if (dimmGroupId >= maxCPUNum)
1536 {
1537 return ipmi::responseInvalidFieldRequest();
1538 }
1539
1540 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1541
1542 if (!cpuStatus)
1543 {
1544 return ipmi::responseInvalidFieldRequest();
1545 }
1546
James Feist91244a62019-02-19 15:04:54 -08001547 boost::container::flat_map<
1548 std::string, std::variant<std::vector<std::string>, std::string>>
1549 profileData;
1550
Vernon Mauery15419dd2019-05-24 09:40:30 -07001551 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1552 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001553 {
James Feist5b693632019-07-09 09:06:09 -07001554 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001555 }
1556
1557 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1558
1559 if (current == nullptr)
1560 {
1561 phosphor::logging::log<phosphor::logging::level::ERR>(
1562 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001563 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001564 }
1565 bool performance = (*current == "Performance");
1566
James Feist5b693632019-07-09 09:06:09 -07001567 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001568 if (performance)
1569 {
James Feist5b693632019-07-09 09:06:09 -07001570 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001571 }
1572
James Feist5b693632019-07-09 09:06:09 -07001573 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001574}
James Feist5f957ca2019-03-14 15:33:55 -07001575constexpr const char* cfmLimitSettingPath =
1576 "/xyz/openbmc_project/control/cfm_limit";
1577constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001578constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001579constexpr const size_t legacyPCHSensorNumber = 0x22;
1580constexpr const char* exitAirPathName = "Exit_Air";
1581constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001582constexpr const char* pidConfigurationIface =
1583 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001584
James Feist09f6b602019-08-08 11:30:03 -07001585static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001586{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001587 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001588 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001589 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1590 "/xyz/openbmc_project/object_mapper",
1591 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001592
James Feistacc8a4e2019-04-02 14:23:57 -07001593 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001594 std::string path;
1595 GetSubTreeType resp;
1596 try
1597 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001598 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001599 reply.read(resp);
1600 }
1601 catch (sdbusplus::exception_t&)
1602 {
1603 phosphor::logging::log<phosphor::logging::level::ERR>(
1604 "ipmiOEMGetFscParameter: mapper error");
1605 };
James Feist09f6b602019-08-08 11:30:03 -07001606 auto config =
1607 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1608 return pair.first.find(name) != std::string::npos;
1609 });
James Feistfaa4f222019-03-21 16:21:55 -07001610 if (config != resp.end())
1611 {
1612 path = std::move(config->first);
1613 }
1614 return path;
1615}
James Feist5f957ca2019-03-14 15:33:55 -07001616
James Feistacc8a4e2019-04-02 14:23:57 -07001617// flat map to make alphabetical
1618static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1619{
1620 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001621 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001622 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001623 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1624 "/xyz/openbmc_project/object_mapper",
1625 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001626
1627 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1628 GetSubTreeType resp;
1629
1630 try
1631 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001632 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001633 reply.read(resp);
1634 }
1635 catch (sdbusplus::exception_t&)
1636 {
1637 phosphor::logging::log<phosphor::logging::level::ERR>(
1638 "getFanConfigPaths: mapper error");
1639 };
1640 for (const auto& [path, objects] : resp)
1641 {
1642 if (objects.empty())
1643 {
1644 continue; // should be impossible
1645 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001646
1647 try
1648 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001649 ret.emplace(path,
1650 getAllDbusProperties(*dbus, objects[0].first, path,
1651 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001652 }
1653 catch (sdbusplus::exception_t& e)
1654 {
1655 phosphor::logging::log<phosphor::logging::level::ERR>(
1656 "getPidConfigs: can't get DbusProperties!",
1657 phosphor::logging::entry("ERR=%s", e.what()));
1658 }
James Feistacc8a4e2019-04-02 14:23:57 -07001659 }
1660 return ret;
1661}
1662
1663ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1664{
1665 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1666 if (data.empty())
1667 {
1668 return ipmi::responseResponseError();
1669 }
1670 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1671 for (const auto& [_, pid] : data)
1672 {
1673 auto findClass = pid.find("Class");
1674 if (findClass == pid.end())
1675 {
1676 phosphor::logging::log<phosphor::logging::level::ERR>(
1677 "ipmiOEMGetFscParameter: found illegal pid "
1678 "configurations");
1679 return ipmi::responseResponseError();
1680 }
1681 std::string type = std::get<std::string>(findClass->second);
1682 if (type == "fan")
1683 {
1684 auto findOutLimit = pid.find("OutLimitMin");
1685 if (findOutLimit == pid.end())
1686 {
1687 phosphor::logging::log<phosphor::logging::level::ERR>(
1688 "ipmiOEMGetFscParameter: found illegal pid "
1689 "configurations");
1690 return ipmi::responseResponseError();
1691 }
1692 // get the min out of all the offsets
1693 minOffset = std::min(
1694 minOffset,
1695 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1696 }
1697 }
1698 if (minOffset == std::numeric_limits<uint8_t>::max())
1699 {
1700 phosphor::logging::log<phosphor::logging::level::ERR>(
1701 "ipmiOEMGetFscParameter: found no fan configurations!");
1702 return ipmi::responseResponseError();
1703 }
1704
1705 return ipmi::responseSuccess(minOffset);
1706}
1707
1708ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1709{
1710 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1711 if (data.empty())
1712 {
1713
1714 phosphor::logging::log<phosphor::logging::level::ERR>(
1715 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1716 return ipmi::responseResponseError();
1717 }
1718
Vernon Mauery15419dd2019-05-24 09:40:30 -07001719 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001720 bool found = false;
1721 for (const auto& [path, pid] : data)
1722 {
1723 auto findClass = pid.find("Class");
1724 if (findClass == pid.end())
1725 {
1726
1727 phosphor::logging::log<phosphor::logging::level::ERR>(
1728 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1729 "configurations");
1730 return ipmi::responseResponseError();
1731 }
1732 std::string type = std::get<std::string>(findClass->second);
1733 if (type == "fan")
1734 {
1735 auto findOutLimit = pid.find("OutLimitMin");
1736 if (findOutLimit == pid.end())
1737 {
1738
1739 phosphor::logging::log<phosphor::logging::level::ERR>(
1740 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1741 "configurations");
1742 return ipmi::responseResponseError();
1743 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001744 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001745 path, pidConfigurationIface, "OutLimitMin",
1746 static_cast<double>(offset));
1747 found = true;
1748 }
1749 }
1750 if (!found)
1751 {
1752 phosphor::logging::log<phosphor::logging::level::ERR>(
1753 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1754 return ipmi::responseResponseError();
1755 }
1756
1757 return ipmi::responseSuccess();
1758}
1759
1760ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1761 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001762{
1763 constexpr const size_t disableLimiting = 0x0;
1764
Vernon Mauery15419dd2019-05-24 09:40:30 -07001765 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001766 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001767 {
James Feist09f6b602019-08-08 11:30:03 -07001768 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001769 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001770 {
James Feist09f6b602019-08-08 11:30:03 -07001771 pathName = exitAirPathName;
1772 }
1773 else if (param1 == legacyPCHSensorNumber)
1774 {
1775 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001776 }
1777 else
1778 {
James Feistacc8a4e2019-04-02 14:23:57 -07001779 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001780 }
James Feist09f6b602019-08-08 11:30:03 -07001781 std::string path = getConfigPath(pathName);
1782 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1783 pidConfigurationIface, "SetPoint",
1784 static_cast<double>(param2));
1785 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001786 }
James Feistacc8a4e2019-04-02 14:23:57 -07001787 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001788 {
James Feistacc8a4e2019-04-02 14:23:57 -07001789 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001790
1791 // must be greater than 50 based on eps
1792 if (cfm < 50 && cfm != disableLimiting)
1793 {
James Feistacc8a4e2019-04-02 14:23:57 -07001794 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001795 }
1796
1797 try
1798 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001799 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001800 cfmLimitIface, "Limit",
1801 static_cast<double>(cfm));
1802 }
1803 catch (sdbusplus::exception_t& e)
1804 {
1805 phosphor::logging::log<phosphor::logging::level::ERR>(
1806 "ipmiOEMSetFscParameter: can't set cfm setting!",
1807 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001808 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001809 }
James Feistacc8a4e2019-04-02 14:23:57 -07001810 return ipmi::responseSuccess();
1811 }
1812 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1813 {
1814 constexpr const size_t maxDomainCount = 8;
1815 uint8_t requestedDomainMask = param1;
1816 boost::container::flat_map data = getPidConfigs();
1817 if (data.empty())
1818 {
1819
1820 phosphor::logging::log<phosphor::logging::level::ERR>(
1821 "ipmiOEMSetFscParameter: found no pid configurations!");
1822 return ipmi::responseResponseError();
1823 }
1824 size_t count = 0;
1825 for (const auto& [path, pid] : data)
1826 {
1827 auto findClass = pid.find("Class");
1828 if (findClass == pid.end())
1829 {
1830
1831 phosphor::logging::log<phosphor::logging::level::ERR>(
1832 "ipmiOEMSetFscParameter: found illegal pid "
1833 "configurations");
1834 return ipmi::responseResponseError();
1835 }
1836 std::string type = std::get<std::string>(findClass->second);
1837 if (type == "fan")
1838 {
1839 if (requestedDomainMask & (1 << count))
1840 {
1841 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001842 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001843 pidConfigurationIface, "OutLimitMax",
1844 static_cast<double>(param2));
1845 }
1846 count++;
1847 }
1848 }
1849 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001850 }
1851 else
1852 {
1853 // todo other command parts possibly
1854 // tcontrol is handled in peci now
1855 // fan speed offset not implemented yet
1856 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001857 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001858 }
1859}
1860
James Feistacc8a4e2019-04-02 14:23:57 -07001861ipmi::RspType<
1862 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1863 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001864{
James Feist09f6b602019-08-08 11:30:03 -07001865 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001866
Vernon Mauery15419dd2019-05-24 09:40:30 -07001867 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001868 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001869 {
James Feistacc8a4e2019-04-02 14:23:57 -07001870 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001871 {
James Feistacc8a4e2019-04-02 14:23:57 -07001872 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001873 }
1874
James Feist09f6b602019-08-08 11:30:03 -07001875 std::string pathName;
1876
1877 if (*param == legacyExitAirSensorNumber)
1878 {
1879 pathName = exitAirPathName;
1880 }
1881 else if (*param == legacyPCHSensorNumber)
1882 {
1883 pathName = pchPathName;
1884 }
1885 else
James Feistfaa4f222019-03-21 16:21:55 -07001886 {
James Feistacc8a4e2019-04-02 14:23:57 -07001887 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001888 }
James Feist09f6b602019-08-08 11:30:03 -07001889
1890 uint8_t setpoint = legacyDefaultSetpoint;
1891 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001892 if (path.size())
1893 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001894 Value val = ipmi::getDbusProperty(
1895 *dbus, "xyz.openbmc_project.EntityManager", path,
1896 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001897 setpoint = std::floor(std::get<double>(val) + 0.5);
1898 }
1899
1900 // old implementation used to return the "default" and current, we
1901 // don't make the default readily available so just make both the
1902 // same
James Feistfaa4f222019-03-21 16:21:55 -07001903
James Feistacc8a4e2019-04-02 14:23:57 -07001904 return ipmi::responseSuccess(
1905 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001906 }
James Feistacc8a4e2019-04-02 14:23:57 -07001907 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1908 {
1909 constexpr const size_t maxDomainCount = 8;
1910
1911 if (!param)
1912 {
1913 return ipmi::responseReqDataLenInvalid();
1914 }
1915 uint8_t requestedDomain = *param;
1916 if (requestedDomain >= maxDomainCount)
1917 {
1918 return ipmi::responseInvalidFieldRequest();
1919 }
1920
1921 boost::container::flat_map data = getPidConfigs();
1922 if (data.empty())
1923 {
1924 phosphor::logging::log<phosphor::logging::level::ERR>(
1925 "ipmiOEMGetFscParameter: found no pid configurations!");
1926 return ipmi::responseResponseError();
1927 }
1928 size_t count = 0;
1929 for (const auto& [_, pid] : data)
1930 {
1931 auto findClass = pid.find("Class");
1932 if (findClass == pid.end())
1933 {
1934 phosphor::logging::log<phosphor::logging::level::ERR>(
1935 "ipmiOEMGetFscParameter: found illegal pid "
1936 "configurations");
1937 return ipmi::responseResponseError();
1938 }
1939 std::string type = std::get<std::string>(findClass->second);
1940 if (type == "fan")
1941 {
1942 if (requestedDomain == count)
1943 {
1944 auto findOutLimit = pid.find("OutLimitMax");
1945 if (findOutLimit == pid.end())
1946 {
1947 phosphor::logging::log<phosphor::logging::level::ERR>(
1948 "ipmiOEMGetFscParameter: found illegal pid "
1949 "configurations");
1950 return ipmi::responseResponseError();
1951 }
1952
1953 return ipmi::responseSuccess(
1954 static_cast<uint8_t>(std::floor(
1955 std::get<double>(findOutLimit->second) + 0.5)));
1956 }
1957 else
1958 {
1959 count++;
1960 }
1961 }
1962 }
1963
1964 return ipmi::responseInvalidFieldRequest();
1965 }
1966 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001967 {
1968
1969 /*
1970 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001971 previous behavior didn't seem to prevent this, ignore the check for
1972 now.
James Feist5f957ca2019-03-14 15:33:55 -07001973
James Feistacc8a4e2019-04-02 14:23:57 -07001974 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001975 {
1976 phosphor::logging::log<phosphor::logging::level::ERR>(
1977 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001978 return IPMI_CC_REQ_DATA_LEN_INVALID;
1979 }
1980 */
1981 Value cfmLimit;
1982 Value cfmMaximum;
1983 try
1984 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001985 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001986 cfmLimitSettingPath, cfmLimitIface,
1987 "Limit");
1988 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001989 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001990 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1991 }
1992 catch (sdbusplus::exception_t& e)
1993 {
1994 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001995 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001996 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001997 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001998 }
1999
James Feistacc8a4e2019-04-02 14:23:57 -07002000 double cfmMax = std::get<double>(cfmMaximum);
2001 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002002
James Feistacc8a4e2019-04-02 14:23:57 -07002003 cfmLim = std::floor(cfmLim + 0.5);
2004 cfmMax = std::floor(cfmMax + 0.5);
2005 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2006 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002007
James Feistacc8a4e2019-04-02 14:23:57 -07002008 return ipmi::responseSuccess(
2009 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002010 }
James Feistacc8a4e2019-04-02 14:23:57 -07002011
James Feist5f957ca2019-03-14 15:33:55 -07002012 else
2013 {
2014 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002015 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002016 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002017 }
2018}
2019
Cheng C Yang773703a2019-08-15 09:41:11 +08002020using crConfigVariant =
2021 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2022
2023int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2024 const crConfigVariant& value,
2025 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2026{
2027 boost::system::error_code ec;
2028 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002029 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002030 "/xyz/openbmc_project/control/power_supply_redundancy",
2031 "org.freedesktop.DBus.Properties", "Set",
2032 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2033 if (ec)
2034 {
2035 phosphor::logging::log<phosphor::logging::level::ERR>(
2036 "Failed to set dbus property to cold redundancy");
2037 return -1;
2038 }
2039
2040 return 0;
2041}
2042
2043int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2044 crConfigVariant& value,
Yong Li19445ab2019-12-20 18:25:29 +08002045 const std::string& service = "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002046 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2047{
2048 boost::system::error_code ec;
2049 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002050 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002051 "/xyz/openbmc_project/control/power_supply_redundancy",
2052 "org.freedesktop.DBus.Properties", "Get",
2053 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2054 if (ec)
2055 {
2056 phosphor::logging::log<phosphor::logging::level::ERR>(
2057 "Failed to get dbus property to cold redundancy");
2058 return -1;
2059 }
2060 return 0;
2061}
2062
2063uint8_t getPSUCount(void)
2064{
2065 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2066 ipmi::Value num;
2067 try
2068 {
2069 num = ipmi::getDbusProperty(
2070 *dbus, "xyz.openbmc_project.PSURedundancy",
2071 "/xyz/openbmc_project/control/power_supply_redundancy",
2072 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2073 }
2074 catch (sdbusplus::exception_t& e)
2075 {
2076 phosphor::logging::log<phosphor::logging::level::ERR>(
2077 "Failed to get PSUNumber property from dbus interface");
2078 return 0;
2079 }
2080 uint8_t* pNum = std::get_if<uint8_t>(&num);
2081 if (!pNum)
2082 {
2083 phosphor::logging::log<phosphor::logging::level::ERR>(
2084 "Error to get PSU Number");
2085 return 0;
2086 }
2087 return *pNum;
2088}
2089
2090bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2091{
2092 if (conf.size() < num)
2093 {
2094 phosphor::logging::log<phosphor::logging::level::ERR>(
2095 "Invalid PSU Ranking");
2096 return false;
2097 }
2098 std::set<uint8_t> confSet;
2099 for (uint8_t i = 0; i < num; i++)
2100 {
2101 if (conf[i] > num)
2102 {
2103 phosphor::logging::log<phosphor::logging::level::ERR>(
2104 "PSU Ranking is larger than current PSU number");
2105 return false;
2106 }
2107 confSet.emplace(conf[i]);
2108 }
2109
2110 if (confSet.size() != num)
2111 {
2112 phosphor::logging::log<phosphor::logging::level::ERR>(
2113 "duplicate PSU Ranking");
2114 return false;
2115 }
2116 return true;
2117}
2118
2119enum class crParameter
2120{
2121 crStatus = 0,
2122 crFeature = 1,
2123 rotationFeature = 2,
2124 rotationAlgo = 3,
2125 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002126 numOfPSU = 5,
2127 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002128};
2129
2130constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2131static const constexpr uint32_t oneDay = 0x15180;
2132static const constexpr uint32_t oneMonth = 0xf53700;
2133static const constexpr uint8_t userSpecific = 0x01;
2134static const constexpr uint8_t crSetCompleted = 0;
2135ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2136 uint8_t parameter,
2137 ipmi::message::Payload& payload)
2138{
2139 switch (static_cast<crParameter>(parameter))
2140 {
2141 case crParameter::crFeature:
2142 {
2143 uint8_t param1;
2144 if (payload.unpack(param1) || !payload.fullyUnpacked())
2145 {
2146 return ipmi::responseReqDataLenInvalid();
2147 }
2148 // ColdRedundancy Enable can only be true or flase
2149 if (param1 > 1)
2150 {
2151 return ipmi::responseInvalidFieldRequest();
2152 }
2153 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2154 static_cast<bool>(param1)))
2155 {
2156 return ipmi::responseResponseError();
2157 }
2158 break;
2159 }
2160 case crParameter::rotationFeature:
2161 {
2162 uint8_t param1;
2163 if (payload.unpack(param1) || !payload.fullyUnpacked())
2164 {
2165 return ipmi::responseReqDataLenInvalid();
2166 }
2167 // Rotation Enable can only be true or false
2168 if (param1 > 1)
2169 {
2170 return ipmi::responseInvalidFieldRequest();
2171 }
2172 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2173 {
2174 return ipmi::responseResponseError();
2175 }
2176 break;
2177 }
2178 case crParameter::rotationAlgo:
2179 {
2180 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2181 std::string algoName;
2182 uint8_t param1;
2183 if (payload.unpack(param1))
2184 {
2185 return ipmi::responseReqDataLenInvalid();
2186 }
2187 switch (param1)
2188 {
2189 case 0:
2190 algoName = "xyz.openbmc_project.Control."
2191 "PowerSupplyRedundancy.Algo.bmcSpecific";
2192 break;
2193 case 1:
2194 algoName = "xyz.openbmc_project.Control."
2195 "PowerSupplyRedundancy.Algo.userSpecific";
2196 break;
2197 default:
2198 return ipmi::responseInvalidFieldRequest();
2199 }
2200 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2201 {
2202 return ipmi::responseResponseError();
2203 }
2204
2205 uint8_t numberOfPSU = getPSUCount();
2206 if (!numberOfPSU)
2207 {
2208 return ipmi::responseResponseError();
2209 }
2210 std::vector<uint8_t> rankOrder;
2211
2212 if (param1 == userSpecific)
2213 {
2214 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2215 {
2216 ipmi::responseReqDataLenInvalid();
2217 }
Yong Li83315132019-10-23 17:42:24 +08002218 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002219 {
2220 return ipmi::responseReqDataLenInvalid();
2221 }
2222
2223 if (!validateCRAlgo(rankOrder, numberOfPSU))
2224 {
2225 return ipmi::responseInvalidFieldRequest();
2226 }
2227 }
2228 else
2229 {
2230 if (rankOrder.size() > 0)
2231 {
2232 return ipmi::responseReqDataLenInvalid();
2233 }
2234 for (uint8_t i = 1; i <= numberOfPSU; i++)
2235 {
2236 rankOrder.emplace_back(i);
2237 }
2238 }
2239 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2240 {
2241 return ipmi::responseResponseError();
2242 }
2243 break;
2244 }
2245 case crParameter::rotationPeriod:
2246 {
2247 // Minimum Rotation period is One day (86400 seconds) and Max
2248 // Rotation Period is 6 month (0xf53700 seconds)
2249 uint32_t period;
2250 if (payload.unpack(period) || !payload.fullyUnpacked())
2251 {
2252 return ipmi::responseReqDataLenInvalid();
2253 }
2254 if ((period < oneDay) || (period > oneMonth))
2255 {
2256 return ipmi::responseInvalidFieldRequest();
2257 }
2258 if (setCRConfig(ctx, "PeriodOfRotation", period))
2259 {
2260 return ipmi::responseResponseError();
2261 }
2262 break;
2263 }
2264 default:
2265 {
2266 return ipmi::response(ccParameterNotSupported);
2267 }
2268 }
2269
2270 // TODO Halfwidth needs to set SetInProgress
2271 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002272 std::string("xyz.openbmc_project.Control."
2273 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002274 {
2275 return ipmi::responseResponseError();
2276 }
2277 return ipmi::responseSuccess(crSetCompleted);
2278}
2279
Yong Li83315132019-10-23 17:42:24 +08002280ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002281 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2282{
2283 crConfigVariant value;
2284 switch (static_cast<crParameter>(parameter))
2285 {
2286 case crParameter::crStatus:
2287 {
2288 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2289 {
2290 return ipmi::responseResponseError();
2291 }
2292 std::string* pStatus = std::get_if<std::string>(&value);
2293 if (!pStatus)
2294 {
2295 phosphor::logging::log<phosphor::logging::level::ERR>(
2296 "Error to get ColdRedundancyStatus property");
2297 return ipmi::responseResponseError();
2298 }
2299 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2300 auto status =
2301 server::PowerSupplyRedundancy::convertStatusFromString(
2302 *pStatus);
2303 switch (status)
2304 {
2305 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002306 return ipmi::responseSuccess(parameter,
2307 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002308
2309 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002310 return ipmi::responseSuccess(parameter,
2311 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002312 default:
2313 phosphor::logging::log<phosphor::logging::level::ERR>(
2314 "Error to get valid status");
2315 return ipmi::responseResponseError();
2316 }
2317 }
2318 case crParameter::crFeature:
2319 {
2320 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2321 {
2322 return ipmi::responseResponseError();
2323 }
2324 bool* pResponse = std::get_if<bool>(&value);
2325 if (!pResponse)
2326 {
2327 phosphor::logging::log<phosphor::logging::level::ERR>(
2328 "Error to get ColdRedundancyEnable property");
2329 return ipmi::responseResponseError();
2330 }
2331
Cheng C Yangf41e3342019-09-10 04:47:23 +08002332 return ipmi::responseSuccess(parameter,
2333 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002334 }
2335 case crParameter::rotationFeature:
2336 {
2337 if (getCRConfig(ctx, "RotationEnabled", value))
2338 {
2339 return ipmi::responseResponseError();
2340 }
2341 bool* pResponse = std::get_if<bool>(&value);
2342 if (!pResponse)
2343 {
2344 phosphor::logging::log<phosphor::logging::level::ERR>(
2345 "Error to get RotationEnabled property");
2346 return ipmi::responseResponseError();
2347 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002348 return ipmi::responseSuccess(parameter,
2349 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002350 }
2351 case crParameter::rotationAlgo:
2352 {
2353 if (getCRConfig(ctx, "RotationAlgorithm", value))
2354 {
2355 return ipmi::responseResponseError();
2356 }
2357
2358 std::string* pAlgo = std::get_if<std::string>(&value);
2359 if (!pAlgo)
2360 {
2361 phosphor::logging::log<phosphor::logging::level::ERR>(
2362 "Error to get RotationAlgorithm property");
2363 return ipmi::responseResponseError();
2364 }
Yong Li83315132019-10-23 17:42:24 +08002365 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002366 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2367 auto algo =
2368 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002369
Cheng C Yang773703a2019-08-15 09:41:11 +08002370 switch (algo)
2371 {
2372 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002373 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002374 break;
2375 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002376 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002377 break;
2378 default:
2379 phosphor::logging::log<phosphor::logging::level::ERR>(
2380 "Error to get valid algo");
2381 return ipmi::responseResponseError();
2382 }
2383
2384 if (getCRConfig(ctx, "RotationRankOrder", value))
2385 {
2386 return ipmi::responseResponseError();
2387 }
2388 std::vector<uint8_t>* pResponse =
2389 std::get_if<std::vector<uint8_t>>(&value);
2390 if (!pResponse)
2391 {
2392 phosphor::logging::log<phosphor::logging::level::ERR>(
2393 "Error to get RotationRankOrder property");
2394 return ipmi::responseResponseError();
2395 }
Yong Li83315132019-10-23 17:42:24 +08002396
Cheng C Yang773703a2019-08-15 09:41:11 +08002397 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002398 std::back_inserter(response));
2399
Cheng C Yangf41e3342019-09-10 04:47:23 +08002400 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002401 }
2402 case crParameter::rotationPeriod:
2403 {
2404 if (getCRConfig(ctx, "PeriodOfRotation", value))
2405 {
2406 return ipmi::responseResponseError();
2407 }
2408 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2409 if (!pResponse)
2410 {
2411 phosphor::logging::log<phosphor::logging::level::ERR>(
2412 "Error to get RotationAlgorithm property");
2413 return ipmi::responseResponseError();
2414 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002415 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002416 }
2417 case crParameter::numOfPSU:
2418 {
2419 uint8_t numberOfPSU = getPSUCount();
2420 if (!numberOfPSU)
2421 {
2422 return ipmi::responseResponseError();
2423 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002424 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002425 }
Yong Li19445ab2019-12-20 18:25:29 +08002426 case crParameter::rotationRankOrderEffective:
2427 {
2428 if (getCRConfig(ctx, "RotationRankOrder", value,
2429 "xyz.openbmc_project.PSURedundancy"))
2430 {
2431 return ipmi::responseResponseError();
2432 }
2433 std::vector<uint8_t>* pResponse =
2434 std::get_if<std::vector<uint8_t>>(&value);
2435 if (!pResponse)
2436 {
2437 phosphor::logging::log<phosphor::logging::level::ERR>(
2438 "Error to get effective RotationRankOrder property");
2439 return ipmi::responseResponseError();
2440 }
2441 return ipmi::responseSuccess(parameter, *pResponse);
2442 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002443 default:
2444 {
2445 return ipmi::response(ccParameterNotSupported);
2446 }
2447 }
2448}
2449
Zhu, Yungebe560b02019-04-21 21:19:21 -04002450ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2451 uint8_t faultState,
2452 uint8_t faultGroup,
2453 std::array<uint8_t, 8>& ledStateData)
2454{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002455 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2456 static const std::array<std::string, maxFaultType> faultNames = {
2457 "faultFan", "faultTemp", "faultPower",
2458 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002459
2460 constexpr uint8_t maxFaultSource = 0x4;
2461 constexpr uint8_t skipLEDs = 0xFF;
2462 constexpr uint8_t pinSize = 64;
2463 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002464 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002465
Zhikui Rence4e73f2019-12-06 13:59:47 -08002466 // same pin names need to be defined in dts file
2467 static const std::array<std::array<std::string, groupSize>, groupNum>
2468 faultLedPinNames = {{
2469 "LED_CPU1_CH1_DIMM1_FAULT",
2470 "LED_CPU1_CH1_DIMM2_FAULT",
2471 "LED_CPU1_CH2_DIMM1_FAULT",
2472 "LED_CPU1_CH2_DIMM2_FAULT",
2473 "LED_CPU1_CH3_DIMM1_FAULT",
2474 "LED_CPU1_CH3_DIMM2_FAULT",
2475 "LED_CPU1_CH4_DIMM1_FAULT",
2476 "LED_CPU1_CH4_DIMM2_FAULT",
2477 "LED_CPU1_CH5_DIMM1_FAULT",
2478 "LED_CPU1_CH5_DIMM2_FAULT",
2479 "LED_CPU1_CH6_DIMM1_FAULT",
2480 "LED_CPU1_CH6_DIMM2_FAULT",
2481 "",
2482 "",
2483 "",
2484 "", // end of group1
2485 "LED_CPU2_CH1_DIMM1_FAULT",
2486 "LED_CPU2_CH1_DIMM2_FAULT",
2487 "LED_CPU2_CH2_DIMM1_FAULT",
2488 "LED_CPU2_CH2_DIMM2_FAULT",
2489 "LED_CPU2_CH3_DIMM1_FAULT",
2490 "LED_CPU2_CH3_DIMM2_FAULT",
2491 "LED_CPU2_CH4_DIMM1_FAULT",
2492 "LED_CPU2_CH4_DIMM2_FAULT",
2493 "LED_CPU2_CH5_DIMM1_FAULT",
2494 "LED_CPU2_CH5_DIMM2_FAULT",
2495 "LED_CPU2_CH6_DIMM1_FAULT",
2496 "LED_CPU2_CH6_DIMM2_FAULT",
2497 "",
2498 "",
2499 "",
2500 "", // endof group2
2501 "LED_CPU3_CH1_DIMM1_FAULT",
2502 "LED_CPU3_CH1_DIMM2_FAULT",
2503 "LED_CPU3_CH2_DIMM1_FAULT",
2504 "LED_CPU3_CH2_DIMM2_FAULT",
2505 "LED_CPU3_CH3_DIMM1_FAULT",
2506 "LED_CPU3_CH3_DIMM2_FAULT",
2507 "LED_CPU3_CH4_DIMM1_FAULT",
2508 "LED_CPU3_CH4_DIMM2_FAULT",
2509 "LED_CPU3_CH5_DIMM1_FAULT",
2510 "LED_CPU3_CH5_DIMM2_FAULT",
2511 "LED_CPU3_CH6_DIMM1_FAULT",
2512 "LED_CPU3_CH6_DIMM2_FAULT",
2513 "",
2514 "",
2515 "",
2516 "", // end of group3
2517 "LED_CPU4_CH1_DIMM1_FAULT",
2518 "LED_CPU4_CH1_DIMM2_FAULT",
2519 "LED_CPU4_CH2_DIMM1_FAULT",
2520 "LED_CPU4_CH2_DIMM2_FAULT",
2521 "LED_CPU4_CH3_DIMM1_FAULT",
2522 "LED_CPU4_CH3_DIMM2_FAULT",
2523 "LED_CPU4_CH4_DIMM1_FAULT",
2524 "LED_CPU4_CH4_DIMM2_FAULT",
2525 "LED_CPU4_CH5_DIMM1_FAULT",
2526 "LED_CPU4_CH5_DIMM2_FAULT",
2527 "LED_CPU4_CH6_DIMM1_FAULT",
2528 "LED_CPU4_CH6_DIMM2_FAULT",
2529 "",
2530 "",
2531 "",
2532 "", // end of group4
2533 "LED_FAN1_FAULT",
2534 "LED_FAN2_FAULT",
2535 "LED_FAN3_FAULT",
2536 "LED_FAN4_FAULT",
2537 "LED_FAN5_FAULT",
2538 "LED_FAN6_FAULT",
2539 "LED_FAN7_FAULT",
2540 "LED_FAN8_FAULT",
2541 "",
2542 "",
2543 "",
2544 "",
2545 "",
2546 "",
2547 "",
2548 "" // end of group5
2549 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002550
Zhikui Rence4e73f2019-12-06 13:59:47 -08002551 // Validate the source, fault type --
2552 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2553 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2554 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2555 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2556 // definition differs based on fault type (Byte 2)
2557 // Type Fan=> Group: 0=FanGroupID, FF-not used
2558 // Byte 5-11 00h, not used
2559 // Byte12 FanLedState [7:0]-Fans 7:0
2560 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2561 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2562 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2563 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2564 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2565 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2566 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2567 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002568 if ((sourceId >= maxFaultSource) ||
2569 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2570 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2571 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2572 {
2573 return ipmi::responseParmOutOfRange();
2574 }
2575
Zhikui Rence4e73f2019-12-06 13:59:47 -08002576 size_t pinGroupOffset = 0;
2577 size_t pinGroupMax = pinSize / groupSize;
2578 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002579 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002580 pinGroupOffset = 4;
2581 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002582 }
2583
2584 switch (RemoteFaultType(faultType))
2585 {
2586 case (RemoteFaultType::fan):
2587 case (RemoteFaultType::memory):
2588 {
2589 if (faultGroup == skipLEDs)
2590 {
2591 return ipmi::responseSuccess();
2592 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002593 // calculate led state bit filed count, each byte has 8bits
2594 // the maximum bits will be 8 * 8 bits
2595 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002596
2597 // assemble ledState
2598 uint64_t ledState = 0;
2599 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002600 for (int i = 0; i < sizeof(ledStateData); i++)
2601 {
2602 ledState = (uint64_t)(ledState << 8);
2603 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2604 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002605 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002606
Zhikui Rence4e73f2019-12-06 13:59:47 -08002607 for (int group = 0; group < pinGroupMax; group++)
2608 {
2609 for (int i = 0; i < groupSize; i++)
2610 { // skip non-existing pins
2611 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2612 {
2613 continue;
2614 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002615
Zhikui Rence4e73f2019-12-06 13:59:47 -08002616 gpiod::line line = gpiod::find_line(
2617 faultLedPinNames[group + pinGroupOffset][i]);
2618 if (!line)
2619 {
2620 phosphor::logging::log<phosphor::logging::level::ERR>(
2621 "Not Find Led Gpio Device!",
2622 phosphor::logging::entry(
2623 "DEVICE=%s",
2624 faultLedPinNames[group + pinGroupOffset][i]
2625 .c_str()));
2626 hasError = true;
2627 continue;
2628 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002629
Zhikui Rence4e73f2019-12-06 13:59:47 -08002630 bool activeHigh =
2631 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2632 try
2633 {
2634 line.request(
2635 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2636 activeHigh
2637 ? 0
2638 : gpiod::line_request::FLAG_ACTIVE_LOW});
2639 line.set_value(ledStateBits[i + group * groupSize]);
2640 }
2641 catch (std::system_error&)
2642 {
2643 phosphor::logging::log<phosphor::logging::level::ERR>(
2644 "Error write Led Gpio Device!",
2645 phosphor::logging::entry(
2646 "DEVICE=%s",
2647 faultLedPinNames[group + pinGroupOffset][i]
2648 .c_str()));
2649 hasError = true;
2650 continue;
2651 }
2652 } // for int i
2653 }
2654 if (hasError)
2655 {
2656 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002657 }
2658 break;
2659 }
2660 default:
2661 {
2662 // now only support two fault types
2663 return ipmi::responseParmOutOfRange();
2664 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002665 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002666 return ipmi::responseSuccess();
2667}
2668
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302669ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2670{
2671 uint8_t prodId = 0;
2672 try
2673 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002674 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302675 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002676 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302677 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2678 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002679 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302680 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2681 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302682 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2683 }
2684 catch (std::exception& e)
2685 {
2686 phosphor::logging::log<phosphor::logging::level::ERR>(
2687 "ipmiOEMReadBoardProductId: Product ID read failed!",
2688 phosphor::logging::entry("ERR=%s", e.what()));
2689 }
2690 return ipmi::responseSuccess(prodId);
2691}
2692
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302693/** @brief implements the get security mode command
2694 * @param ctx - ctx pointer
2695 *
2696 * @returns IPMI completion code with following data
2697 * - restriction mode value - As specified in
2698 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2699 * - special mode value - As specified in
2700 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2701 */
2702ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2703{
2704 namespace securityNameSpace =
2705 sdbusplus::xyz::openbmc_project::Control::Security::server;
2706 uint8_t restrictionModeValue = 0;
2707 uint8_t specialModeValue = 0;
2708
2709 boost::system::error_code ec;
2710 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002711 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302712 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2713 restricionModeProperty);
2714 if (ec)
2715 {
2716 phosphor::logging::log<phosphor::logging::level::ERR>(
2717 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2718 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2719 return ipmi::responseUnspecifiedError();
2720 }
2721 restrictionModeValue = static_cast<uint8_t>(
2722 securityNameSpace::RestrictionMode::convertModesFromString(
2723 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302724 auto varSpecialMode =
2725 ctx->bus->yield_method_call<std::variant<std::string>>(
2726 ctx->yield, ec, specialModeService, specialModeBasePath,
2727 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2728 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302729 if (ec)
2730 {
2731 phosphor::logging::log<phosphor::logging::level::ERR>(
2732 "ipmiGetSecurityMode: failed to get SpecialMode property",
2733 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2734 // fall through, let us not worry about SpecialMode property, which is
2735 // not required in user scenario
2736 }
2737 else
2738 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302739 specialModeValue = static_cast<uint8_t>(
2740 securityNameSpace::SpecialMode::convertModesFromString(
2741 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302742 }
2743 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2744}
2745
2746/** @brief implements the set security mode command
2747 * Command allows to upgrade the restriction mode and won't allow
2748 * to downgrade from system interface
2749 * @param ctx - ctx pointer
2750 * @param restrictionMode - restriction mode value to be set.
2751 *
2752 * @returns IPMI completion code
2753 */
2754ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302755 uint8_t restrictionMode,
2756 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302757{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302758#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2759 if (specialMode)
2760 {
2761 return ipmi::responseReqDataLenInvalid();
2762 }
2763#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302764 namespace securityNameSpace =
2765 sdbusplus::xyz::openbmc_project::Control::Security::server;
2766
2767 ChannelInfo chInfo;
2768 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2769 {
2770 phosphor::logging::log<phosphor::logging::level::ERR>(
2771 "ipmiSetSecurityMode: Failed to get Channel Info",
2772 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2773 return ipmi::responseUnspecifiedError();
2774 }
2775 auto reqMode =
2776 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2777
2778 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2779 (reqMode >
2780 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2781 {
2782 return ipmi::responseInvalidFieldRequest();
2783 }
2784
2785 boost::system::error_code ec;
2786 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002787 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302788 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2789 restricionModeProperty);
2790 if (ec)
2791 {
2792 phosphor::logging::log<phosphor::logging::level::ERR>(
2793 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2794 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2795 return ipmi::responseUnspecifiedError();
2796 }
2797 auto currentRestrictionMode =
2798 securityNameSpace::RestrictionMode::convertModesFromString(
2799 std::get<std::string>(varRestrMode));
2800
2801 if (chInfo.mediumType !=
2802 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2803 currentRestrictionMode > reqMode)
2804 {
2805 phosphor::logging::log<phosphor::logging::level::ERR>(
2806 "ipmiSetSecurityMode - Downgrading security mode not supported "
2807 "through system interface",
2808 phosphor::logging::entry(
2809 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2810 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2811 return ipmi::responseCommandNotAvailable();
2812 }
2813
2814 ec.clear();
2815 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002816 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302817 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2818 restricionModeProperty,
2819 static_cast<std::variant<std::string>>(
2820 securityNameSpace::convertForMessage(reqMode)));
2821
2822 if (ec)
2823 {
2824 phosphor::logging::log<phosphor::logging::level::ERR>(
2825 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2826 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2827 return ipmi::responseUnspecifiedError();
2828 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302829
2830#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2831 if (specialMode)
2832 {
2833 ec.clear();
2834 ctx->bus->yield_method_call<>(
2835 ctx->yield, ec, specialModeService, specialModeBasePath,
2836 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2837 specialModeProperty,
2838 static_cast<std::variant<std::string>>(
2839 securityNameSpace::convertForMessage(
2840 static_cast<securityNameSpace::SpecialMode::Modes>(
2841 specialMode.value()))));
2842
2843 if (ec)
2844 {
2845 phosphor::logging::log<phosphor::logging::level::ERR>(
2846 "ipmiSetSecurityMode: failed to set SpecialMode property",
2847 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2848 return ipmi::responseUnspecifiedError();
2849 }
2850 }
2851#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302852 return ipmi::responseSuccess();
2853}
2854
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002855ipmi::RspType<uint8_t /* restore status */>
2856 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2857{
2858 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2859
2860 if (clr != expClr)
2861 {
2862 return ipmi::responseInvalidFieldRequest();
2863 }
2864 constexpr uint8_t cmdStatus = 0;
2865 constexpr uint8_t cmdDefaultRestore = 0xaa;
2866 constexpr uint8_t cmdFullRestore = 0xbb;
2867 constexpr uint8_t cmdFormat = 0xcc;
2868
2869 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2870
2871 switch (cmd)
2872 {
2873 case cmdStatus:
2874 break;
2875 case cmdDefaultRestore:
2876 case cmdFullRestore:
2877 case cmdFormat:
2878 {
2879 // write file to rwfs root
2880 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2881 std::ofstream restoreFile(restoreOpFname);
2882 if (!restoreFile)
2883 {
2884 return ipmi::responseUnspecifiedError();
2885 }
2886 restoreFile << value << "\n";
2887 break;
2888 }
2889 default:
2890 return ipmi::responseInvalidFieldRequest();
2891 }
2892
2893 constexpr uint8_t restorePending = 0;
2894 constexpr uint8_t restoreComplete = 1;
2895
2896 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2897 ? restorePending
2898 : restoreComplete;
2899 return ipmi::responseSuccess(restoreStatus);
2900}
2901
Chen Yugang39736d52019-07-12 16:24:33 +08002902ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2903{
2904 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002905 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002906
2907 try
2908 {
2909 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2910 std::string service =
2911 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2912 Value variant =
2913 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2914 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2915
2916 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2917 std::get<std::string>(variant)))
2918 {
2919 case nmi::NMISource::BMCSourceSignal::None:
2920 bmcSource = static_cast<uint8_t>(NmiSource::none);
2921 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002922 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2923 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002924 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002925 case nmi::NMISource::BMCSourceSignal::Watchdog:
2926 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002927 break;
2928 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2929 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2930 break;
2931 case nmi::NMISource::BMCSourceSignal::MemoryError:
2932 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2933 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002934 case nmi::NMISource::BMCSourceSignal::PciBusError:
2935 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002936 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002937 case nmi::NMISource::BMCSourceSignal::PCH:
2938 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002939 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002940 case nmi::NMISource::BMCSourceSignal::Chipset:
2941 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002942 break;
2943 default:
2944 phosphor::logging::log<phosphor::logging::level::ERR>(
2945 "NMI source: invalid property!",
2946 phosphor::logging::entry(
2947 "PROP=%s", std::get<std::string>(variant).c_str()));
2948 return ipmi::responseResponseError();
2949 }
2950 }
2951 catch (sdbusplus::exception::SdBusError& e)
2952 {
2953 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2954 return ipmi::responseResponseError();
2955 }
2956
2957 return ipmi::responseSuccess(bmcSource);
2958}
2959
2960ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2961{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002962 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002963
2964 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2965 nmi::NMISource::BMCSourceSignal::None;
2966
2967 switch (NmiSource(sourceId))
2968 {
2969 case NmiSource::none:
2970 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2971 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002972 case NmiSource::frontPanelButton:
2973 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08002974 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002975 case NmiSource::watchdog:
2976 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08002977 break;
2978 case NmiSource::chassisCmd:
2979 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2980 break;
2981 case NmiSource::memoryError:
2982 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2983 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002984 case NmiSource::pciBusError:
2985 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08002986 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002987 case NmiSource::pch:
2988 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08002989 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002990 case NmiSource::chipset:
2991 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08002992 break;
2993 default:
2994 phosphor::logging::log<phosphor::logging::level::ERR>(
2995 "NMI source: invalid property!");
2996 return ipmi::responseResponseError();
2997 }
2998
2999 try
3000 {
3001 // keep NMI signal source
3002 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3003 std::string service =
3004 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003005 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3006 oemNmiBmcSourceObjPathProp,
3007 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003008 // set Enabled property to inform NMI source handling
3009 // to trigger a NMI_OUT BSOD.
3010 // if it's triggered by NMI source property changed,
3011 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3012 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3013 {
3014 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3015 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3016 static_cast<bool>(true));
3017 }
Chen Yugang39736d52019-07-12 16:24:33 +08003018 }
3019 catch (sdbusplus::exception_t& e)
3020 {
3021 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3022 return ipmi::responseResponseError();
3023 }
3024
3025 return ipmi::responseSuccess();
3026}
3027
James Feist63efafa2019-07-24 12:39:21 -07003028namespace dimmOffset
3029{
3030constexpr const char* dimmPower = "DimmPower";
3031constexpr const char* staticCltt = "StaticCltt";
3032constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3033constexpr const char* offsetInterface =
3034 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3035constexpr const char* property = "DimmOffset";
3036
3037}; // namespace dimmOffset
3038
3039ipmi::RspType<>
3040 ipmiOEMSetDimmOffset(uint8_t type,
3041 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3042{
3043 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3044 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3045 {
3046 return ipmi::responseInvalidFieldRequest();
3047 }
3048
3049 if (data.empty())
3050 {
3051 return ipmi::responseInvalidFieldRequest();
3052 }
3053 nlohmann::json json;
3054
3055 std::ifstream jsonStream(dimmOffsetFile);
3056 if (jsonStream.good())
3057 {
3058 json = nlohmann::json::parse(jsonStream, nullptr, false);
3059 if (json.is_discarded())
3060 {
3061 json = nlohmann::json();
3062 }
3063 jsonStream.close();
3064 }
3065
3066 std::string typeName;
3067 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3068 {
3069 typeName = dimmOffset::dimmPower;
3070 }
3071 else
3072 {
3073 typeName = dimmOffset::staticCltt;
3074 }
3075
3076 nlohmann::json& field = json[typeName];
3077
3078 for (const auto& [index, value] : data)
3079 {
3080 field[index] = value;
3081 }
3082
3083 for (nlohmann::json& val : field)
3084 {
3085 if (val == nullptr)
3086 {
3087 val = static_cast<uint8_t>(0);
3088 }
3089 }
3090
3091 std::ofstream output(dimmOffsetFile);
3092 if (!output.good())
3093 {
3094 std::cerr << "Error writing json file\n";
3095 return ipmi::responseResponseError();
3096 }
3097
3098 output << json.dump(4);
3099
3100 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3101 {
3102 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3103
3104 std::variant<std::vector<uint8_t>> offsets =
3105 field.get<std::vector<uint8_t>>();
3106 auto call = bus->new_method_call(
3107 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3108 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3109 try
3110 {
3111 bus->call(call);
3112 }
3113 catch (sdbusplus::exception_t& e)
3114 {
3115 phosphor::logging::log<phosphor::logging::level::ERR>(
3116 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3117 phosphor::logging::entry("ERR=%s", e.what()));
3118 return ipmi::responseResponseError();
3119 }
3120 }
3121
3122 return ipmi::responseSuccess();
3123}
3124
3125ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3126{
3127
3128 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3129 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3130 {
3131 return ipmi::responseInvalidFieldRequest();
3132 }
3133
3134 std::ifstream jsonStream(dimmOffsetFile);
3135
3136 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3137 if (json.is_discarded())
3138 {
3139 std::cerr << "File error in " << dimmOffsetFile << "\n";
3140 return ipmi::responseResponseError();
3141 }
3142
3143 std::string typeName;
3144 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3145 {
3146 typeName = dimmOffset::dimmPower;
3147 }
3148 else
3149 {
3150 typeName = dimmOffset::staticCltt;
3151 }
3152
3153 auto it = json.find(typeName);
3154 if (it == json.end())
3155 {
3156 return ipmi::responseInvalidFieldRequest();
3157 }
3158
3159 if (it->size() <= index)
3160 {
3161 return ipmi::responseInvalidFieldRequest();
3162 }
3163
3164 uint8_t resp = it->at(index).get<uint8_t>();
3165 return ipmi::responseSuccess(resp);
3166}
3167
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003168namespace boot_options
3169{
3170
3171using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3172using IpmiValue = uint8_t;
3173constexpr auto ipmiDefault = 0;
3174
3175std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3176 {0x01, Source::Sources::Network},
3177 {0x02, Source::Sources::Disk},
3178 {0x05, Source::Sources::ExternalMedia},
3179 {0x0f, Source::Sources::RemovableMedia},
3180 {ipmiDefault, Source::Sources::Default}};
3181
3182std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003183 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003184
3185std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3186 {Source::Sources::Network, 0x01},
3187 {Source::Sources::Disk, 0x02},
3188 {Source::Sources::ExternalMedia, 0x05},
3189 {Source::Sources::RemovableMedia, 0x0f},
3190 {Source::Sources::Default, ipmiDefault}};
3191
3192std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003193 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003194
3195static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3196static constexpr auto bootSourceIntf =
3197 "xyz.openbmc_project.Control.Boot.Source";
3198static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3199static constexpr auto persistentObjPath =
3200 "/xyz/openbmc_project/control/host0/boot";
3201static constexpr auto oneTimePath =
3202 "/xyz/openbmc_project/control/host0/boot/one_time";
3203static constexpr auto bootSourceProp = "BootSource";
3204static constexpr auto bootModeProp = "BootMode";
3205static constexpr auto oneTimeBootEnableProp = "Enabled";
3206static constexpr auto httpBootMode =
3207 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3208
3209enum class BootOptionParameter : size_t
3210{
3211 setInProgress = 0x0,
3212 bootFlags = 0x5,
3213};
3214static constexpr uint8_t setComplete = 0x0;
3215static constexpr uint8_t setInProgress = 0x1;
3216static uint8_t transferStatus = setComplete;
3217static constexpr uint8_t setParmVersion = 0x01;
3218static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3219static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3220static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3221static constexpr uint8_t httpBoot = 0xd;
3222static constexpr uint8_t bootSourceMask = 0x3c;
3223
3224} // namespace boot_options
3225
3226ipmi::RspType<uint8_t, // version
3227 uint8_t, // param
3228 uint8_t, // data0, dependent on parameter
3229 std::optional<uint8_t> // data1, dependent on parameter
3230 >
3231 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3232{
3233 using namespace boot_options;
3234 uint8_t bootOption = 0;
3235
3236 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3237 {
3238 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3239 std::nullopt);
3240 }
3241
3242 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3243 {
3244 phosphor::logging::log<phosphor::logging::level::ERR>(
3245 "Unsupported parameter");
3246 return ipmi::responseResponseError();
3247 }
3248
3249 try
3250 {
3251 auto oneTimeEnabled = false;
3252 // read one time Enabled property
3253 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3254 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3255 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3256 enabledIntf, oneTimeBootEnableProp);
3257 oneTimeEnabled = std::get<bool>(variant);
3258
3259 // get BootSource and BootMode properties
3260 // according to oneTimeEnable
3261 auto bootObjPath = oneTimePath;
3262 if (oneTimeEnabled == false)
3263 {
3264 bootObjPath = persistentObjPath;
3265 }
3266
3267 service = getService(*dbus, bootModeIntf, bootObjPath);
3268 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3269 bootModeProp);
3270
3271 auto bootMode =
3272 Mode::convertModesFromString(std::get<std::string>(variant));
3273
3274 service = getService(*dbus, bootSourceIntf, bootObjPath);
3275 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3276 bootSourceProp);
3277
3278 if (std::get<std::string>(variant) == httpBootMode)
3279 {
3280 bootOption = httpBoot;
3281 }
3282 else
3283 {
3284 auto bootSource = Source::convertSourcesFromString(
3285 std::get<std::string>(variant));
3286 bootOption = sourceDbusToIpmi.at(bootSource);
3287 if (Source::Sources::Default == bootSource)
3288 {
3289 bootOption = modeDbusToIpmi.at(bootMode);
3290 }
3291 }
3292
3293 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3294 : setParmBootFlagsValidPermanent;
3295 bootOption <<= 2; // shift for responseconstexpr
3296 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3297 bootOption);
3298 }
3299 catch (sdbusplus::exception_t& e)
3300 {
3301 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3302 return ipmi::responseResponseError();
3303 }
3304}
3305
3306ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3307 std::optional<uint8_t> bootOption)
3308{
3309 using namespace boot_options;
3310 auto oneTimeEnabled = false;
3311
3312 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3313 {
3314 if (bootOption)
3315 {
3316 return ipmi::responseReqDataLenInvalid();
3317 }
3318
3319 if (transferStatus == setInProgress)
3320 {
3321 phosphor::logging::log<phosphor::logging::level::ERR>(
3322 "boot option set in progress!");
3323 return ipmi::responseResponseError();
3324 }
3325
3326 transferStatus = bootParam;
3327 return ipmi::responseSuccess();
3328 }
3329
3330 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3331 {
3332 phosphor::logging::log<phosphor::logging::level::ERR>(
3333 "Unsupported parameter");
3334 return ipmi::responseResponseError();
3335 }
3336
3337 if (!bootOption)
3338 {
3339 return ipmi::responseReqDataLenInvalid();
3340 }
3341
3342 if (((bootOption.value() & bootSourceMask) >> 2) !=
3343 httpBoot) // not http boot, exit
3344 {
3345 phosphor::logging::log<phosphor::logging::level::ERR>(
3346 "wrong boot option parameter!");
3347 return ipmi::responseParmOutOfRange();
3348 }
3349
3350 try
3351 {
3352 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3353 setParmBootFlagsPermanent;
3354
3355 // read one time Enabled property
3356 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3357 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3358 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3359 enabledIntf, oneTimeBootEnableProp);
3360 oneTimeEnabled = std::get<bool>(variant);
3361
3362 /*
3363 * Check if the current boot setting is onetime or permanent, if the
3364 * request in the command is otherwise, then set the "Enabled"
3365 * property in one_time object path to 'True' to indicate onetime
3366 * and 'False' to indicate permanent.
3367 *
3368 * Once the onetime/permanent setting is applied, then the bootMode
3369 * and bootSource is updated for the corresponding object.
3370 */
3371 if (permanent == oneTimeEnabled)
3372 {
3373 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3374 oneTimeBootEnableProp, !permanent);
3375 }
3376
3377 // set BootSource and BootMode properties
3378 // according to oneTimeEnable or persistent
3379 auto bootObjPath = oneTimePath;
3380 if (oneTimeEnabled == false)
3381 {
3382 bootObjPath = persistentObjPath;
3383 }
3384 std::string bootMode =
3385 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3386 std::string bootSource = httpBootMode;
3387
3388 service = getService(*dbus, bootModeIntf, bootObjPath);
3389 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3390 bootMode);
3391
3392 service = getService(*dbus, bootSourceIntf, bootObjPath);
3393 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3394 bootSourceProp, bootSource);
3395 }
3396 catch (sdbusplus::exception_t& e)
3397 {
3398 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3399 return ipmi::responseResponseError();
3400 }
3401
3402 return ipmi::responseSuccess();
3403}
3404
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003405using BasicVariantType =
3406 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3407 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3408 uint16_t, uint8_t, bool>;
3409using PropertyMapType =
3410 boost::container::flat_map<std::string, BasicVariantType>;
3411static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3412 "xyz.openbmc_project.Configuration.PSUPresence"};
3413int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3414 std::vector<uint64_t>& addrTable)
3415{
3416 boost::system::error_code ec;
3417 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3418 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3419 "/xyz/openbmc_project/object_mapper",
3420 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3421 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3422 if (ec)
3423 {
3424 phosphor::logging::log<phosphor::logging::level::ERR>(
3425 "Failed to set dbus property to cold redundancy");
3426 return -1;
3427 }
3428 for (const auto& object : subtree)
3429 {
3430 std::string pathName = object.first;
3431 for (const auto& serviceIface : object.second)
3432 {
3433 std::string serviceName = serviceIface.first;
3434
3435 ec.clear();
3436 PropertyMapType propMap =
3437 ctx->bus->yield_method_call<PropertyMapType>(
3438 ctx->yield, ec, serviceName, pathName,
3439 "org.freedesktop.DBus.Properties", "GetAll",
3440 "xyz.openbmc_project.Configuration.PSUPresence");
3441 if (ec)
3442 {
3443 phosphor::logging::log<phosphor::logging::level::ERR>(
3444 "Failed to set dbus property to cold redundancy");
3445 return -1;
3446 }
3447 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3448 auto psuAddress =
3449 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3450
3451 if (psuBus == nullptr || psuAddress == nullptr)
3452 {
3453 std::cerr << "error finding necessary "
3454 "entry in configuration\n";
3455 return -1;
3456 }
3457 bus = static_cast<uint8_t>(*psuBus);
3458 addrTable = *psuAddress;
3459 return 0;
3460 }
3461 }
3462 return -1;
3463}
3464
3465static const constexpr uint8_t addrOffset = 8;
3466static const constexpr uint8_t psuRevision = 0xd9;
3467static const constexpr uint8_t defaultPSUBus = 7;
3468// Second Minor, Primary Minor, Major
3469static const constexpr size_t verLen = 3;
3470ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3471{
3472 uint8_t bus = defaultPSUBus;
3473 std::vector<uint64_t> addrTable;
3474 std::vector<uint8_t> result;
3475 if (getPSUAddress(ctx, bus, addrTable))
3476 {
3477 std::cerr << "Failed to get PSU bus and address\n";
3478 return ipmi::responseResponseError();
3479 }
3480
3481 for (const auto& slaveAddr : addrTable)
3482 {
3483 std::vector<uint8_t> writeData = {psuRevision};
3484 std::vector<uint8_t> readBuf(verLen);
3485 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3486 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3487
3488 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3489 if (retI2C != ipmi::ccSuccess)
3490 {
3491 for (size_t idx = 0; idx < verLen; idx++)
3492 {
3493 result.emplace_back(0x00);
3494 }
3495 }
3496 else
3497 {
3498 for (const uint8_t& data : readBuf)
3499 {
3500 result.emplace_back(data);
3501 }
3502 }
3503 }
3504
3505 return ipmi::responseSuccess(result);
3506}
3507
AppaRao Puli28972062019-11-11 02:04:45 +05303508/** @brief implements the maximum size of
3509 * bridgeable messages used between KCS and
3510 * IPMB interfacesget security mode command.
3511 *
3512 * @returns IPMI completion code with following data
3513 * - KCS Buffer Size (In multiples of four bytes)
3514 * - IPMB Buffer Size (In multiples of four bytes)
3515 **/
3516ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3517{
3518 // for now this is hard coded; really this number is dependent on
3519 // the BMC kcs driver as well as the host kcs driver....
3520 // we can't know the latter.
3521 uint8_t kcsMaxBufferSize = 63 / 4;
3522 uint8_t ipmbMaxBufferSize = 128 / 4;
3523
3524 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3525}
3526
Jason M. Bills64796042018-10-03 16:51:55 -07003527static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003528{
3529 phosphor::logging::log<phosphor::logging::level::INFO>(
3530 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003531 ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003532 ipmiOEMWildcard,
3533 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003534
3535 ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003536 ipmiOEMWildcard,
3537 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003538
3539 ipmiPrintAndRegister(intel::netFnGeneral,
3540 intel::general::cmdGetChassisIdentifier, NULL,
3541 ipmiOEMGetChassisIdentifier,
3542 PRIVILEGE_USER); // get chassis identifier
3543
3544 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3545 NULL, ipmiOEMSetSystemGUID,
3546 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003547
3548 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003549 registerHandler(prioOemBase, intel::netFnGeneral,
3550 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3551 ipmiOEMDisableBMCSystemReset);
3552
Jason M. Billsb02bf092019-08-15 13:01:56 -07003553 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003554 registerHandler(prioOemBase, intel::netFnGeneral,
3555 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3556 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003557
Vernon Mauery98bbf692019-09-16 11:14:59 -07003558 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3559 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003560
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003561 registerHandler(prioOemBase, intel::netFnGeneral,
3562 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3563 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003564
Vernon Mauery98bbf692019-09-16 11:14:59 -07003565 ipmiPrintAndRegister(intel::netFnGeneral,
3566 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3567 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303568
Vernon Mauery98bbf692019-09-16 11:14:59 -07003569 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3570 intel::general::cmdSendEmbeddedFWUpdStatus,
3571 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303572
Vernon Mauery98bbf692019-09-16 11:14:59 -07003573 ipmiPrintAndRegister(intel::netFnGeneral,
3574 intel::general::cmdSetPowerRestoreDelay, NULL,
3575 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3576
3577 ipmiPrintAndRegister(intel::netFnGeneral,
3578 intel::general::cmdGetPowerRestoreDelay, NULL,
3579 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3580
3581 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3582 intel::general::cmdSetOEMUser2Activation,
3583 Privilege::Callback, ipmiOEMSetUser2Activation);
3584
3585 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3586 intel::general::cmdSetSpecialUserPassword,
3587 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303588
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003589 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003590 registerHandler(prioOemBase, intel::netFnGeneral,
3591 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3592 ipmiOEMGetProcessorErrConfig);
3593
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003594 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003595 registerHandler(prioOemBase, intel::netFnGeneral,
3596 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3597 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003598
Vernon Mauery98bbf692019-09-16 11:14:59 -07003599 ipmiPrintAndRegister(intel::netFnGeneral,
3600 intel::general::cmdSetShutdownPolicy, NULL,
3601 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003602
Vernon Mauery98bbf692019-09-16 11:14:59 -07003603 ipmiPrintAndRegister(intel::netFnGeneral,
3604 intel::general::cmdGetShutdownPolicy, NULL,
3605 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003606
anil kumar appanaf945eee2019-09-25 23:29:11 +00003607 registerHandler(prioOemBase, intel::netFnGeneral,
3608 intel::general::cmdSetFanConfig, Privilege::User,
3609 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003610
Vernon Mauery98bbf692019-09-16 11:14:59 -07003611 registerHandler(prioOemBase, intel::netFnGeneral,
3612 intel::general::cmdGetFanConfig, Privilege::User,
3613 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003614
Vernon Mauery98bbf692019-09-16 11:14:59 -07003615 registerHandler(prioOemBase, intel::netFnGeneral,
3616 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3617 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003618
Vernon Mauery98bbf692019-09-16 11:14:59 -07003619 registerHandler(prioOemBase, intel::netFnGeneral,
3620 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3621 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003622
Vernon Mauery98bbf692019-09-16 11:14:59 -07003623 registerHandler(prioOemBase, intel::netFnGeneral,
3624 intel::general::cmdSetFscParameter, Privilege::User,
3625 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003626
Vernon Mauery98bbf692019-09-16 11:14:59 -07003627 registerHandler(prioOemBase, intel::netFnGeneral,
3628 intel::general::cmdGetFscParameter, Privilege::User,
3629 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303630
Vernon Mauery98bbf692019-09-16 11:14:59 -07003631 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3632 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3633 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003634
Vernon Mauery98bbf692019-09-16 11:14:59 -07003635 registerHandler(prioOemBase, intel::netFnGeneral,
3636 intel::general::cmdGetNmiStatus, Privilege::User,
3637 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003638
Vernon Mauery98bbf692019-09-16 11:14:59 -07003639 registerHandler(prioOemBase, intel::netFnGeneral,
3640 intel::general::cmdSetNmiStatus, Privilege::Operator,
3641 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003642
Vernon Mauery98bbf692019-09-16 11:14:59 -07003643 registerHandler(prioOemBase, intel::netFnGeneral,
3644 intel::general::cmdGetEfiBootOptions, Privilege::User,
3645 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003646
Vernon Mauery98bbf692019-09-16 11:14:59 -07003647 registerHandler(prioOemBase, intel::netFnGeneral,
3648 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3649 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303650
Vernon Mauery98bbf692019-09-16 11:14:59 -07003651 registerHandler(prioOemBase, intel::netFnGeneral,
3652 intel::general::cmdGetSecurityMode, Privilege::User,
3653 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303654
Vernon Mauery98bbf692019-09-16 11:14:59 -07003655 registerHandler(prioOemBase, intel::netFnGeneral,
3656 intel::general::cmdSetSecurityMode, Privilege::Admin,
3657 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003658
Vernon Mauery98bbf692019-09-16 11:14:59 -07003659 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3660 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003661
Vernon Mauery98bbf692019-09-16 11:14:59 -07003662 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3663 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3664 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3665
3666 registerHandler(prioOemBase, intel::netFnGeneral,
3667 intel::general::cmdSetFaultIndication, Privilege::Operator,
3668 ipmiOEMSetFaultIndication);
3669
3670 registerHandler(prioOemBase, intel::netFnGeneral,
3671 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3672 ipmiOEMSetCRConfig);
3673
3674 registerHandler(prioOemBase, intel::netFnGeneral,
3675 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3676 ipmiOEMGetCRConfig);
3677
3678 registerHandler(prioOemBase, intel::netFnGeneral,
3679 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003680 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003681
Vernon Mauery98bbf692019-09-16 11:14:59 -07003682 registerHandler(prioOemBase, intel::netFnGeneral,
3683 intel::general::cmdSetDimmOffset, Privilege::Operator,
3684 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003685
Vernon Mauery98bbf692019-09-16 11:14:59 -07003686 registerHandler(prioOemBase, intel::netFnGeneral,
3687 intel::general::cmdGetDimmOffset, Privilege::Operator,
3688 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003689
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003690 registerHandler(prioOemBase, intel::netFnGeneral,
3691 intel::general::cmdGetPSUVersion, Privilege::User,
3692 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303693
3694 registerHandler(prioOemBase, intel::netFnGeneral,
3695 intel::general::cmdGetBufferSize, Privilege::User,
3696 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003697}
3698
3699} // namespace ipmi