blob: e531a8c2874222b38ad9a645a445ca7b3e091ac5 [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",
AppaRao Pulid46cb422020-01-21 18:40:21 +0530339 "/xyz/openbmc_project/software/me");
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800340 Value variant =
AppaRao Pulid46cb422020-01-21 18:40:21 +0530341 getDbusProperty(*dbus, service, "/xyz/openbmc_project/software/me",
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800342 "xyz.openbmc_project.Software.Version", "Version");
343
AppaRao Pulid46cb422020-01-21 18:40:21 +0530344 std::string& meVersion = std::get<std::string>(variant);
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800345
346 // get ME major number
347 std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)");
348 constexpr size_t matchedPhosphor = 6;
349 std::smatch results;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530350 if (std::regex_match(meVersion, results, pattern1))
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800351 {
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>>>>
AppaRao Pulid46cb422020-01-21 18:40:21 +0530372 ipmiOEMGetDeviceInfo(uint8_t entityType, std::optional<uint8_t> countToRead,
373 std::optional<uint8_t> offset)
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800374{
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800375 if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
376 {
377 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800378 }
379
380 // handle OEM command items
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800381 switch (OEMDevEntityType(entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800382 {
383 case OEMDevEntityType::biosId:
384 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530385 // Byte 2&3, Only used with selecting BIOS
386 if (!countToRead || !offset)
387 {
388 return ipmi::responseReqDataLenInvalid();
389 }
390
Vernon Mauery15419dd2019-05-24 09:40:30 -0700391 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li2742b852019-12-16 14:55:11 +0800392 std::string service =
393 getService(*dbus, biosVersionIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800394 try
395 {
Yong Li2742b852019-12-16 14:55:11 +0800396 Value variant =
397 getDbusProperty(*dbus, service, biosObjPath,
398 biosVersionIntf, biosVersionProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700399 std::string& idString = std::get<std::string>(variant);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530400 if (*offset >= idString.size())
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800401 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800402 return ipmi::responseParmOutOfRange();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800403 }
Jason M. Bills64796042018-10-03 16:51:55 -0700404 size_t length = 0;
AppaRao Pulid46cb422020-01-21 18:40:21 +0530405 if (*countToRead > (idString.size() - *offset))
Jason M. Bills64796042018-10-03 16:51:55 -0700406 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530407 length = idString.size() - *offset;
Jason M. Bills64796042018-10-03 16:51:55 -0700408 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800409 else
410 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530411 length = *countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800412 }
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800413
414 std::string readBuf = {0};
415 readBuf.resize(length);
AppaRao Pulid46cb422020-01-21 18:40:21 +0530416 std::copy_n(idString.begin() + *offset, length,
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800417 (readBuf.begin()));
418 return ipmi::responseSuccess(readBuf);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800419 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700420 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800421 {
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800422 return ipmi::responseUnspecifiedError();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800423 }
424 }
425 break;
426
427 case OEMDevEntityType::devVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800428 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530429 // Byte 2&3, Only used with selecting BIOS
430 if (countToRead || offset)
431 {
432 return ipmi::responseReqDataLenInvalid();
433 }
434
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800435 constexpr const size_t verLen = 2;
436 constexpr const size_t verTotalLen = 10;
437 std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff};
438 std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff};
439 std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff};
440 std::array<uint8_t, verLen> meBuf = {0xff, 0xff};
441 std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff};
442 // data0/1: BMC version number; data6/7: ME version number
443 // the others: HSC0/1/2 version number, not avaible.
444 if (true != getSwVerInfo(bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1]))
445 {
446 return ipmi::responseUnspecifiedError();
447 }
448 return ipmi::responseSuccess(
449 std::tuple<
450 uint8_t, std::array<uint8_t, verLen>,
451 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>,
452 std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{
453 verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf});
454 }
455 break;
456
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800457 case OEMDevEntityType::sdrVer:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800458 {
AppaRao Pulid46cb422020-01-21 18:40:21 +0530459 // Byte 2&3, Only used with selecting BIOS
460 if (countToRead || offset)
461 {
462 return ipmi::responseReqDataLenInvalid();
463 }
464
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800465 constexpr const size_t sdrLen = 2;
466 std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0};
467 return ipmi::responseSuccess(
468 std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen,
469 readBuf});
470 }
471 break;
472
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800473 default:
Chen Yugang7a04f3a2019-10-08 11:12:35 +0800474 return ipmi::responseInvalidFieldRequest();
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800475 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800476}
477
478ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
479 ipmi_request_t request, ipmi_response_t response,
480 ipmi_data_len_t dataLen, ipmi_context_t context)
481{
482 if (*dataLen != 0)
483 {
Jason M. Bills64796042018-10-03 16:51:55 -0700484 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800485 return IPMI_CC_REQ_DATA_LEN_INVALID;
486 }
487
488 *dataLen = 1;
489 uint8_t* res = reinterpret_cast<uint8_t*>(response);
490 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
491 // AIC is available so that BIOS will not timeout repeatly which leads to
492 // slow booting.
493 *res = 0; // Byte1=Count of SlotPosition/FruID records.
494 return IPMI_CC_OK;
495}
496
Jason M. Bills64796042018-10-03 16:51:55 -0700497ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
498 ipmi_request_t request,
499 ipmi_response_t response,
500 ipmi_data_len_t dataLen,
501 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800502{
Jason M. Bills64796042018-10-03 16:51:55 -0700503 GetPowerRestoreDelayRes* resp =
504 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
505
506 if (*dataLen != 0)
507 {
508 *dataLen = 0;
509 return IPMI_CC_REQ_DATA_LEN_INVALID;
510 }
511
Vernon Mauery15419dd2019-05-24 09:40:30 -0700512 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700513 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700514 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700515 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700516 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700517 powerRestoreDelayIntf, powerRestoreDelayProp);
518
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700519 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700520 resp->byteLSB = delay;
521 resp->byteMSB = delay >> 8;
522
523 *dataLen = sizeof(GetPowerRestoreDelayRes);
524
525 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800526}
527
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800528static uint8_t bcdToDec(uint8_t val)
529{
530 return ((val / 16 * 10) + (val % 16));
531}
532
533// Allows an update utility or system BIOS to send the status of an embedded
534// firmware update attempt to the BMC. After received, BMC will create a logging
535// record.
536ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
537 uint8_t majorRevision,
538 uint8_t minorRevision,
539 uint32_t auxInfo)
540{
541 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700542 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800543 target = (target & selEvtTargetMask) >> selEvtTargetShift;
544
545 /* make sure the status is 0, 1, or 2 as per the spec */
546 if (status > 2)
547 {
548 return ipmi::response(ipmi::ccInvalidFieldRequest);
549 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700550 /* make sure the target is 0, 1, 2, or 4 as per the spec */
551 if (target > 4 || target == 3)
552 {
553 return ipmi::response(ipmi::ccInvalidFieldRequest);
554 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800555 /*orignal OEM command is to record OEM SEL.
556 But openbmc does not support OEM SEL, so we redirect it to redfish event
557 logging. */
558 std::string buildInfo;
559 std::string action;
560 switch (FWUpdateTarget(target))
561 {
562 case FWUpdateTarget::targetBMC:
563 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700564 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800565 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
566 " BuildID: " + std::to_string(auxInfo);
567 buildInfo += std::to_string(auxInfo);
568 break;
569 case FWUpdateTarget::targetBIOS:
570 firmware = "BIOS";
571 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700572 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800573 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
574 " minor: " +
575 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
576 " ReleaseNumber: " + // ASCII encoded
577 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
578 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
579 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
580 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
581 break;
582 case FWUpdateTarget::targetME:
583 firmware = "ME";
584 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700585 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800586 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
587 " minor2: " +
588 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
589 " build1: " +
590 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
591 " build2: " +
592 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
593 break;
594 case FWUpdateTarget::targetOEMEWS:
595 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700596 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800597 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
598 " BuildID: " + std::to_string(auxInfo);
599 break;
600 }
601
Jason M. Billsdc249272019-04-03 09:58:40 -0700602 static const std::string openBMCMessageRegistryVersion("0.1");
603 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
604
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800605 switch (status)
606 {
607 case 0x0:
608 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700609 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800610 break;
611 case 0x1:
612 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700613 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800614 break;
615 case 0x2:
616 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700617 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800618 break;
619 default:
620 action = "unknown";
621 break;
622 }
623
Jason M. Billsdc249272019-04-03 09:58:40 -0700624 std::string firmwareInstanceStr =
625 firmware + " instance: " + std::to_string(instance);
626 std::string message("[firmware update] " + firmwareInstanceStr +
627 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800628
629 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700630 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
631 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
632 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800633 return ipmi::responseSuccess();
634}
635
Jason M. Bills64796042018-10-03 16:51:55 -0700636ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
637 ipmi_request_t request,
638 ipmi_response_t response,
639 ipmi_data_len_t dataLen,
640 ipmi_context_t context)
641{
642 SetPowerRestoreDelayReq* data =
643 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
644 uint16_t delay = 0;
645
646 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
647 {
648 *dataLen = 0;
649 return IPMI_CC_REQ_DATA_LEN_INVALID;
650 }
651 delay = data->byteMSB;
652 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700653 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700654 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700655 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
656 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700657 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
658 *dataLen = 0;
659
660 return IPMI_CC_OK;
661}
662
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700663static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700664{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700665 static constexpr const char* cpuPresencePathPrefix =
666 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
667 static constexpr const char* cpuPresenceIntf =
668 "xyz.openbmc_project.Inventory.Item";
669 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
670 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
671 try
Jason M. Bills64796042018-10-03 16:51:55 -0700672 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700673 auto service =
674 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
675
676 ipmi::Value result = ipmi::getDbusProperty(
677 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
678 return std::get<bool>(result);
679 }
680 catch (const std::exception& e)
681 {
682 phosphor::logging::log<phosphor::logging::level::INFO>(
683 "Cannot find processor presence",
684 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
685 return false;
686 }
687}
688
689ipmi::RspType<bool, // CATERR Reset Enabled
690 bool, // ERR2 Reset Enabled
691 uint6_t, // reserved
692 uint8_t, // reserved, returns 0x3F
693 uint6_t, // CPU1 CATERR Count
694 uint2_t, // CPU1 Status
695 uint6_t, // CPU2 CATERR Count
696 uint2_t, // CPU2 Status
697 uint6_t, // CPU3 CATERR Count
698 uint2_t, // CPU3 Status
699 uint6_t, // CPU4 CATERR Count
700 uint2_t, // CPU4 Status
701 uint8_t // Crashdump Count
702 >
703 ipmiOEMGetProcessorErrConfig()
704{
705 bool resetOnCATERR = false;
706 bool resetOnERR2 = false;
707 uint6_t cpu1CATERRCount = 0;
708 uint6_t cpu2CATERRCount = 0;
709 uint6_t cpu3CATERRCount = 0;
710 uint6_t cpu4CATERRCount = 0;
711 uint8_t crashdumpCount = 0;
712 uint2_t cpu1Status =
713 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
714 uint2_t cpu2Status =
715 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
716 uint2_t cpu3Status =
717 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
718 uint2_t cpu4Status =
719 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
720
721 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
722 try
723 {
724 auto service = ipmi::getService(*busp, processorErrConfigIntf,
725 processorErrConfigObjPath);
726
727 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
728 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
729 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
730 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
731 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
732 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
733 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
734 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
735 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
736 }
737 catch (const std::exception& e)
738 {
739 phosphor::logging::log<phosphor::logging::level::ERR>(
740 "Failed to fetch processor error config",
741 phosphor::logging::entry("ERROR=%s", e.what()));
742 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700743 }
744
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700745 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
746 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
747 cpu2Status, cpu3CATERRCount, cpu3Status,
748 cpu4CATERRCount, cpu4Status, crashdumpCount);
749}
Jason M. Bills64796042018-10-03 16:51:55 -0700750
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700751ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
752 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
753 std::optional<bool> clearCPUErrorCount,
754 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
755{
756 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700757
758 try
759 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700760 auto service = ipmi::getService(*busp, processorErrConfigIntf,
761 processorErrConfigObjPath);
762 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
763 processorErrConfigIntf, "ResetOnCATERR",
764 resetOnCATERR);
765 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
766 processorErrConfigIntf, "ResetOnERR2",
767 resetOnERR2);
768 if (clearCPUErrorCount.value_or(false))
769 {
770 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700771 processorErrConfigIntf, "ErrorCountCPU1",
772 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700773 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700774 processorErrConfigIntf, "ErrorCountCPU2",
775 static_cast<uint8_t>(0));
776 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
777 processorErrConfigIntf, "ErrorCountCPU3",
778 static_cast<uint8_t>(0));
779 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
780 processorErrConfigIntf, "ErrorCountCPU4",
781 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700782 }
783 if (clearCrashdumpCount.value_or(false))
784 {
785 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700786 processorErrConfigIntf, "CrashdumpCount",
787 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700788 }
Jason M. Bills64796042018-10-03 16:51:55 -0700789 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700790 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700791 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800792 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700793 "Failed to set processor error config",
794 phosphor::logging::entry("EXCEPTION=%s", e.what()));
795 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700796 }
797
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700798 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700799}
800
Yong Li703922d2018-11-06 13:25:31 +0800801ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
802 ipmi_request_t request,
803 ipmi_response_t response,
804 ipmi_data_len_t dataLen,
805 ipmi_context_t context)
806{
807 GetOEMShutdownPolicyRes* resp =
808 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
809
810 if (*dataLen != 0)
811 {
812 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800813 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800814 *dataLen = 0;
815 return IPMI_CC_REQ_DATA_LEN_INVALID;
816 }
817
818 *dataLen = 0;
819
820 try
821 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700822 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800823 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700824 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
825 Value variant = getDbusProperty(
826 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
827 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800828
829 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
830 convertPolicyFromString(std::get<std::string>(variant)) ==
831 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
832 NoShutdownOnOCOT)
833 {
834 resp->policy = 0;
835 }
836 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
837 convertPolicyFromString(std::get<std::string>(variant)) ==
838 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
839 Policy::ShutdownOnOCOT)
840 {
841 resp->policy = 1;
842 }
843 else
844 {
845 phosphor::logging::log<phosphor::logging::level::ERR>(
846 "oem_set_shutdown_policy: invalid property!",
847 phosphor::logging::entry(
848 "PROP=%s", std::get<std::string>(variant).c_str()));
849 return IPMI_CC_UNSPECIFIED_ERROR;
850 }
Yong Li703922d2018-11-06 13:25:31 +0800851 // TODO needs to check if it is multi-node products,
852 // policy is only supported on node 3/4
853 resp->policySupport = shutdownPolicySupported;
854 }
855 catch (sdbusplus::exception_t& e)
856 {
857 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
858 return IPMI_CC_UNSPECIFIED_ERROR;
859 }
860
861 *dataLen = sizeof(GetOEMShutdownPolicyRes);
862 return IPMI_CC_OK;
863}
864
865ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
866 ipmi_request_t request,
867 ipmi_response_t response,
868 ipmi_data_len_t dataLen,
869 ipmi_context_t context)
870{
871 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800872 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
873 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
874 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800875
876 // TODO needs to check if it is multi-node products,
877 // policy is only supported on node 3/4
878 if (*dataLen != 1)
879 {
880 phosphor::logging::log<phosphor::logging::level::ERR>(
881 "oem_set_shutdown_policy: invalid input len!");
882 *dataLen = 0;
883 return IPMI_CC_REQ_DATA_LEN_INVALID;
884 }
885
886 *dataLen = 0;
887 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
888 {
889 phosphor::logging::log<phosphor::logging::level::ERR>(
890 "oem_set_shutdown_policy: invalid input!");
891 return IPMI_CC_INVALID_FIELD_REQUEST;
892 }
893
Yong Li0669d192019-05-06 14:01:46 +0800894 if (*req == noShutdownOnOCOT)
895 {
896 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
897 Policy::NoShutdownOnOCOT;
898 }
899 else
900 {
901 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
902 Policy::ShutdownOnOCOT;
903 }
904
Yong Li703922d2018-11-06 13:25:31 +0800905 try
906 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700907 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800908 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700909 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800910 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700911 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800912 oemShutdownPolicyObjPathProp,
913 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800914 }
915 catch (sdbusplus::exception_t& e)
916 {
917 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
918 return IPMI_CC_UNSPECIFIED_ERROR;
919 }
920
921 return IPMI_CC_OK;
922}
923
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530924/** @brief implementation for check the DHCP or not in IPv4
925 * @param[in] Channel - Channel number
926 * @returns true or false.
927 */
928static bool isDHCPEnabled(uint8_t Channel)
929{
930 try
931 {
932 auto ethdevice = getChannelName(Channel);
933 if (ethdevice.empty())
934 {
935 return false;
936 }
937 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700938 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530939 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700940 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
941 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530942 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700943 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530944 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
945 {
946 return true;
947 }
948 else
949 {
950 return false;
951 }
952 }
953 catch (sdbusplus::exception_t& e)
954 {
955 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
956 return true;
957 }
958}
959
960/** @brief implementes for check the DHCP or not in IPv6
961 * @param[in] Channel - Channel number
962 * @returns true or false.
963 */
964static bool isDHCPIPv6Enabled(uint8_t Channel)
965{
966
967 try
968 {
969 auto ethdevice = getChannelName(Channel);
970 if (ethdevice.empty())
971 {
972 return false;
973 }
974 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700975 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530976 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700977 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
978 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530979 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700980 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530981 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
982 {
983 return true;
984 }
985 else
986 {
987 return false;
988 }
989 }
990 catch (sdbusplus::exception_t& e)
991 {
992 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
993 return true;
994 }
995}
996
997/** @brief implementes the creating of default new user
998 * @param[in] userName - new username in 16 bytes.
999 * @param[in] userPassword - new password in 20 bytes
1000 * @returns ipmi completion code.
1001 */
1002ipmi::RspType<> ipmiOEMSetUser2Activation(
1003 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
1004 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
1005{
1006 bool userState = false;
1007 // Check for System Interface not exist and LAN should be static
1008 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
1009 {
1010 ChannelInfo chInfo;
1011 try
1012 {
1013 getChannelInfo(channel, chInfo);
1014 }
1015 catch (sdbusplus::exception_t& e)
1016 {
1017 phosphor::logging::log<phosphor::logging::level::ERR>(
1018 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
1019 phosphor::logging::entry("MSG: %s", e.description()));
1020 return ipmi::response(ipmi::ccUnspecifiedError);
1021 }
1022 if (chInfo.mediumType ==
1023 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1024 {
1025 phosphor::logging::log<phosphor::logging::level::ERR>(
1026 "ipmiOEMSetUser2Activation: system interface exist .");
1027 return ipmi::response(ipmi::ccCommandNotAvailable);
1028 }
1029 else
1030 {
1031
1032 if (chInfo.mediumType ==
1033 static_cast<uint8_t>(EChannelMediumType::lan8032))
1034 {
1035 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
1036 {
1037 phosphor::logging::log<phosphor::logging::level::ERR>(
1038 "ipmiOEMSetUser2Activation: DHCP enabled .");
1039 return ipmi::response(ipmi::ccCommandNotAvailable);
1040 }
1041 }
1042 }
1043 }
1044 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
1045 if (ipmi::ccSuccess ==
1046 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
1047 {
1048 if (enabledUsers > 1)
1049 {
1050 phosphor::logging::log<phosphor::logging::level::ERR>(
1051 "ipmiOEMSetUser2Activation: more than one user is enabled.");
1052 return ipmi::response(ipmi::ccCommandNotAvailable);
1053 }
1054 // Check the user 2 is enabled or not
1055 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
1056 if (userState == true)
1057 {
1058 phosphor::logging::log<phosphor::logging::level::ERR>(
1059 "ipmiOEMSetUser2Activation: user 2 already enabled .");
1060 return ipmi::response(ipmi::ccCommandNotAvailable);
1061 }
1062 }
1063 else
1064 {
1065 return ipmi::response(ipmi::ccUnspecifiedError);
1066 }
1067
1068#if BYTE_ORDER == LITTLE_ENDIAN
1069 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
1070#endif
1071#if BYTE_ORDER == BIG_ENDIAN
1072 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
1073#endif
1074
1075 if (ipmi::ccSuccess ==
1076 ipmiUserSetUserName(ipmiDefaultUserId,
1077 reinterpret_cast<const char*>(userName.data())))
1078 {
1079 if (ipmi::ccSuccess ==
1080 ipmiUserSetUserPassword(
1081 ipmiDefaultUserId,
1082 reinterpret_cast<const char*>(userPassword.data())))
1083 {
1084 if (ipmi::ccSuccess ==
1085 ipmiUserSetPrivilegeAccess(
1086 ipmiDefaultUserId,
1087 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
1088 privAccess, true))
1089 {
1090 phosphor::logging::log<phosphor::logging::level::INFO>(
1091 "ipmiOEMSetUser2Activation: user created successfully ");
1092 return ipmi::responseSuccess();
1093 }
1094 }
1095 // we need to delete the default user id which added in this command as
1096 // password / priv setting is failed.
1097 ipmiUserSetUserName(ipmiDefaultUserId, "");
1098 phosphor::logging::log<phosphor::logging::level::ERR>(
1099 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
1100 }
1101 else
1102 {
1103 phosphor::logging::log<phosphor::logging::level::ERR>(
1104 "ipmiOEMSetUser2Activation: Setting username failed.");
1105 }
1106
1107 return ipmi::response(ipmi::ccCommandNotAvailable);
1108}
1109
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301110/** @brief implementes executing the linux command
1111 * @param[in] linux command
1112 * @returns status
1113 */
1114
1115static uint8_t executeCmd(const char* path)
1116{
1117 boost::process::child execProg(path);
1118 execProg.wait();
1119
1120 int retCode = execProg.exit_code();
1121 if (retCode)
1122 {
1123 return ipmi::ccUnspecifiedError;
1124 }
1125 return ipmi::ccSuccess;
1126}
1127
1128/** @brief implementes ASD Security event logging
1129 * @param[in] Event message string
1130 * @param[in] Event Severity
1131 * @returns status
1132 */
1133
1134static void atScaleDebugEventlog(std::string msg, int severity)
1135{
1136 std::string eventStr = "OpenBMC.0.1." + msg;
1137 sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(),
1138 "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s",
1139 eventStr.c_str(), NULL);
1140}
1141
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301142/** @brief implementes setting password for special user
1143 * @param[in] specialUserIndex
1144 * @param[in] userPassword - new password in 20 bytes
1145 * @returns ipmi completion code.
1146 */
1147ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
1148 uint8_t specialUserIndex,
1149 std::vector<uint8_t> userPassword)
1150{
1151 ChannelInfo chInfo;
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301152 ipmi_ret_t status = ipmi::ccSuccess;
1153
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301154 try
1155 {
1156 getChannelInfo(ctx->channel, chInfo);
1157 }
1158 catch (sdbusplus::exception_t& e)
1159 {
1160 phosphor::logging::log<phosphor::logging::level::ERR>(
1161 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1162 phosphor::logging::entry("MSG: %s", e.description()));
1163 return ipmi::responseUnspecifiedError();
1164 }
1165 if (chInfo.mediumType !=
1166 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1167 {
1168 phosphor::logging::log<phosphor::logging::level::ERR>(
1169 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1170 "interface");
1171 return ipmi::responseCommandNotAvailable();
1172 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301173
1174 // 0 for root user and 1 for AtScaleDebug is allowed
1175 if (specialUserIndex >
1176 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301177 {
1178 phosphor::logging::log<phosphor::logging::level::ERR>(
1179 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1180 return ipmi::responseParmOutOfRange();
1181 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301182 if (userPassword.size() != 0)
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301183 {
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301184 constexpr uint8_t minPasswordSizeRequired = 6;
1185 std::string passwd;
1186 if (userPassword.size() < minPasswordSizeRequired ||
1187 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1188 {
1189 return ipmi::responseReqDataLenInvalid();
1190 }
1191 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1192 userPassword.size());
1193 if (specialUserIndex ==
1194 static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser))
1195 {
1196 status = ipmiSetSpecialUserPassword("asdbg", passwd);
1197
1198 atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT);
1199 }
1200 else
1201 {
1202 status = ipmiSetSpecialUserPassword("root", passwd);
1203 }
1204 return ipmi::response(status);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301205 }
Suryakanth Sekar822b0b42019-11-15 18:32:53 +05301206 else
1207 {
1208 if (specialUserIndex ==
1209 static_cast<uint8_t>(SpecialUserIndex::rootUser))
1210 {
1211 status = executeCmd("passwd -d root");
1212 }
1213 else
1214 {
1215
1216 status = executeCmd("passwd -d asdbg");
1217
1218 if (status == 0)
1219 {
1220 atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled",
1221 LOG_INFO);
1222 }
1223 }
1224 return ipmi::response(status);
1225 }
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301226}
1227
Kuiying Wang45f04982018-12-26 09:23:08 +08001228namespace ledAction
1229{
1230using namespace sdbusplus::xyz::openbmc_project::Led::server;
1231std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
jayaprakash Mutyala934ee9c2019-12-13 17:49:27 +00001232 {Physical::Action::Off, 0},
1233 {Physical::Action::On, 2},
1234 {Physical::Action::Blink, 1}};
Kuiying Wang45f04982018-12-26 09:23:08 +08001235
1236std::map<uint8_t, std::string> offsetObjPath = {
1237 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1238
1239} // namespace ledAction
1240
1241int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1242 const std::string& objPath, uint8_t& state)
1243{
1244 try
1245 {
1246 std::string service = getService(bus, intf, objPath);
1247 Value stateValue =
1248 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001249 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001250 state = ledAction::actionDbusToIpmi.at(
1251 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1252 convertActionFromString(strState));
1253 }
1254 catch (sdbusplus::exception::SdBusError& e)
1255 {
1256 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1257 return -1;
1258 }
1259 return 0;
1260}
1261
1262ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1263 ipmi_request_t request, ipmi_response_t response,
1264 ipmi_data_len_t dataLen, ipmi_context_t context)
1265{
1266 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1267 // LED Status
1268 //[1:0] = Reserved
1269 //[3:2] = Status(Amber)
1270 //[5:4] = Status(Green)
1271 //[7:6] = System Identify
1272 // Status definitions:
1273 // 00b = Off
1274 // 01b = Blink
1275 // 10b = On
1276 // 11b = invalid
1277 if (*dataLen != 0)
1278 {
1279 phosphor::logging::log<phosphor::logging::level::ERR>(
1280 "oem_get_led_status: invalid input len!");
1281 *dataLen = 0;
1282 return IPMI_CC_REQ_DATA_LEN_INVALID;
1283 }
1284
1285 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1286 *resp = 0;
1287 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001288 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001289 for (auto it = ledAction::offsetObjPath.begin();
1290 it != ledAction::offsetObjPath.end(); ++it)
1291 {
1292 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001293 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001294 {
1295 phosphor::logging::log<phosphor::logging::level::ERR>(
1296 "oem_get_led_status: fail to get ID LED status!");
1297 return IPMI_CC_UNSPECIFIED_ERROR;
1298 }
1299 *resp |= state << it->first;
1300 }
1301
1302 *dataLen = sizeof(*resp);
1303 return IPMI_CC_OK;
1304}
1305
Yong Li23737fe2019-02-19 08:49:55 +08001306ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1307 ipmi_request_t request,
1308 ipmi_response_t response,
1309 ipmi_data_len_t dataLen,
1310 ipmi_context_t context)
1311{
1312 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1313 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1314
1315 if (*dataLen == 0)
1316 {
1317 phosphor::logging::log<phosphor::logging::level::ERR>(
1318 "CfgHostSerial: invalid input len!",
1319 phosphor::logging::entry("LEN=%d", *dataLen));
1320 return IPMI_CC_REQ_DATA_LEN_INVALID;
1321 }
1322
1323 switch (req->command)
1324 {
1325 case getHostSerialCfgCmd:
1326 {
1327 if (*dataLen != 1)
1328 {
1329 phosphor::logging::log<phosphor::logging::level::ERR>(
1330 "CfgHostSerial: invalid input len!");
1331 *dataLen = 0;
1332 return IPMI_CC_REQ_DATA_LEN_INVALID;
1333 }
1334
1335 *dataLen = 0;
1336
1337 boost::process::ipstream is;
1338 std::vector<std::string> data;
1339 std::string line;
1340 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1341 boost::process::std_out > is);
1342
1343 while (c1.running() && std::getline(is, line) && !line.empty())
1344 {
1345 data.push_back(line);
1346 }
1347
1348 c1.wait();
1349 if (c1.exit_code())
1350 {
1351 phosphor::logging::log<phosphor::logging::level::ERR>(
1352 "CfgHostSerial:: error on execute",
1353 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1354 // Using the default value
1355 *resp = 0;
1356 }
1357 else
1358 {
1359 if (data.size() != 1)
1360 {
1361 phosphor::logging::log<phosphor::logging::level::ERR>(
1362 "CfgHostSerial:: error on read env");
1363 return IPMI_CC_UNSPECIFIED_ERROR;
1364 }
1365 try
1366 {
1367 unsigned long tmp = std::stoul(data[0]);
1368 if (tmp > std::numeric_limits<uint8_t>::max())
1369 {
1370 throw std::out_of_range("Out of range");
1371 }
1372 *resp = static_cast<uint8_t>(tmp);
1373 }
1374 catch (const std::invalid_argument& e)
1375 {
1376 phosphor::logging::log<phosphor::logging::level::ERR>(
1377 "invalid config ",
1378 phosphor::logging::entry("ERR=%s", e.what()));
1379 return IPMI_CC_UNSPECIFIED_ERROR;
1380 }
1381 catch (const std::out_of_range& e)
1382 {
1383 phosphor::logging::log<phosphor::logging::level::ERR>(
1384 "out_of_range config ",
1385 phosphor::logging::entry("ERR=%s", e.what()));
1386 return IPMI_CC_UNSPECIFIED_ERROR;
1387 }
1388 }
1389
1390 *dataLen = 1;
1391 break;
1392 }
1393 case setHostSerialCfgCmd:
1394 {
1395 if (*dataLen != sizeof(CfgHostSerialReq))
1396 {
1397 phosphor::logging::log<phosphor::logging::level::ERR>(
1398 "CfgHostSerial: invalid input len!");
1399 *dataLen = 0;
1400 return IPMI_CC_REQ_DATA_LEN_INVALID;
1401 }
1402
1403 *dataLen = 0;
1404
1405 if (req->parameter > HostSerialCfgParamMax)
1406 {
1407 phosphor::logging::log<phosphor::logging::level::ERR>(
1408 "CfgHostSerial: invalid input!");
1409 return IPMI_CC_INVALID_FIELD_REQUEST;
1410 }
1411
1412 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1413 std::to_string(req->parameter));
1414
1415 c1.wait();
1416 if (c1.exit_code())
1417 {
1418 phosphor::logging::log<phosphor::logging::level::ERR>(
1419 "CfgHostSerial:: error on execute",
1420 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1421 return IPMI_CC_UNSPECIFIED_ERROR;
1422 }
1423 break;
1424 }
1425 default:
1426 phosphor::logging::log<phosphor::logging::level::ERR>(
1427 "CfgHostSerial: invalid input!");
1428 *dataLen = 0;
1429 return IPMI_CC_INVALID_FIELD_REQUEST;
1430 }
1431
1432 return IPMI_CC_OK;
1433}
1434
James Feist91244a62019-02-19 15:04:54 -08001435constexpr const char* thermalModeInterface =
1436 "xyz.openbmc_project.Control.ThermalMode";
1437constexpr const char* thermalModePath =
1438 "/xyz/openbmc_project/control/thermal_mode";
1439
1440bool getFanProfileInterface(
1441 sdbusplus::bus::bus& bus,
1442 boost::container::flat_map<
1443 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1444{
1445 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1446 "GetAll");
1447 call.append(thermalModeInterface);
1448 try
1449 {
1450 auto data = bus.call(call);
1451 data.read(resp);
1452 }
1453 catch (sdbusplus::exception_t& e)
1454 {
1455 phosphor::logging::log<phosphor::logging::level::ERR>(
1456 "getFanProfileInterface: can't get thermal mode!",
1457 phosphor::logging::entry("ERR=%s", e.what()));
1458 return false;
1459 }
1460 return true;
1461}
1462
anil kumar appanaf945eee2019-09-25 23:29:11 +00001463/**@brief implements the OEM set fan config.
1464 * @param selectedFanProfile - fan profile to enable
1465 * @param reserved1
1466 * @param performanceMode - Performance/Acoustic mode
1467 * @param reserved2
1468 * @param setPerformanceMode - set Performance/Acoustic mode
1469 * @param setFanProfile - set fan profile
1470 *
1471 * @return IPMI completion code.
1472 **/
1473ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile,
1474
1475 uint2_t reserved1, bool performanceMode,
1476 uint3_t reserved2, bool setPerformanceMode,
1477 bool setFanProfile)
James Feist91244a62019-02-19 15:04:54 -08001478{
anil kumar appanaf945eee2019-09-25 23:29:11 +00001479 if (reserved1 || reserved2)
James Feist91244a62019-02-19 15:04:54 -08001480 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001481 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001482 }
James Feist91244a62019-02-19 15:04:54 -08001483 // todo: tell bios to only send first 2 bytes
James Feist91244a62019-02-19 15:04:54 -08001484 boost::container::flat_map<
1485 std::string, std::variant<std::vector<std::string>, std::string>>
1486 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001487 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1488 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001489 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001490 return ipmi::responseUnspecifiedError();
James Feist91244a62019-02-19 15:04:54 -08001491 }
1492
1493 std::vector<std::string>* supported =
1494 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1495 if (supported == nullptr)
1496 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001497 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001498 }
1499 std::string mode;
anil kumar appanaf945eee2019-09-25 23:29:11 +00001500 if (setPerformanceMode)
James Feist91244a62019-02-19 15:04:54 -08001501 {
James Feist91244a62019-02-19 15:04:54 -08001502 if (performanceMode)
1503 {
1504
1505 if (std::find(supported->begin(), supported->end(),
1506 "Performance") != supported->end())
1507 {
1508 mode = "Performance";
1509 }
1510 }
1511 else
1512 {
James Feist91244a62019-02-19 15:04:54 -08001513 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1514 supported->end())
1515 {
1516 mode = "Acoustic";
1517 }
1518 }
1519 if (mode.empty())
1520 {
anil kumar appanaf945eee2019-09-25 23:29:11 +00001521 return ipmi::responseInvalidFieldRequest();
James Feist91244a62019-02-19 15:04:54 -08001522 }
anil kumar appanaf945eee2019-09-25 23:29:11 +00001523
1524 try
1525 {
1526 setDbusProperty(*dbus, settingsBusName, thermalModePath,
1527 thermalModeInterface, "Current", mode);
1528 }
1529 catch (sdbusplus::exception_t& e)
1530 {
1531 phosphor::logging::log<phosphor::logging::level::ERR>(
1532 "ipmiOEMSetFanConfig: can't set thermal mode!",
1533 phosphor::logging::entry("EXCEPTION=%s", e.what()));
1534 return ipmi::responseResponseError();
1535 }
James Feist91244a62019-02-19 15:04:54 -08001536 }
1537
anil kumar appanaf945eee2019-09-25 23:29:11 +00001538 return ipmi::responseSuccess();
James Feist91244a62019-02-19 15:04:54 -08001539}
1540
James Feist5b693632019-07-09 09:06:09 -07001541ipmi::RspType<uint8_t, // profile support map
1542 uint8_t, // fan control profile enable
1543 uint8_t, // flags
1544 uint32_t // dimm presence bit map
1545 >
1546 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001547{
Joshi-Mansi36f05ce2020-01-14 14:29:34 +05301548 if (dimmGroupId >= maxCPUNum)
1549 {
1550 return ipmi::responseInvalidFieldRequest();
1551 }
1552
1553 bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1));
1554
1555 if (!cpuStatus)
1556 {
1557 return ipmi::responseInvalidFieldRequest();
1558 }
1559
James Feist91244a62019-02-19 15:04:54 -08001560 boost::container::flat_map<
1561 std::string, std::variant<std::vector<std::string>, std::string>>
1562 profileData;
1563
Vernon Mauery15419dd2019-05-24 09:40:30 -07001564 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1565 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001566 {
James Feist5b693632019-07-09 09:06:09 -07001567 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001568 }
1569
1570 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1571
1572 if (current == nullptr)
1573 {
1574 phosphor::logging::log<phosphor::logging::level::ERR>(
1575 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001576 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001577 }
1578 bool performance = (*current == "Performance");
1579
James Feist5b693632019-07-09 09:06:09 -07001580 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001581 if (performance)
1582 {
James Feist5b693632019-07-09 09:06:09 -07001583 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001584 }
1585
James Feist5b693632019-07-09 09:06:09 -07001586 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001587}
James Feist5f957ca2019-03-14 15:33:55 -07001588constexpr const char* cfmLimitSettingPath =
1589 "/xyz/openbmc_project/control/cfm_limit";
1590constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001591constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001592constexpr const size_t legacyPCHSensorNumber = 0x22;
1593constexpr const char* exitAirPathName = "Exit_Air";
1594constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001595constexpr const char* pidConfigurationIface =
1596 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001597
James Feist09f6b602019-08-08 11:30:03 -07001598static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001599{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001600 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001601 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001602 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1603 "/xyz/openbmc_project/object_mapper",
1604 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001605
James Feistacc8a4e2019-04-02 14:23:57 -07001606 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001607 std::string path;
1608 GetSubTreeType resp;
1609 try
1610 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001611 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001612 reply.read(resp);
1613 }
1614 catch (sdbusplus::exception_t&)
1615 {
1616 phosphor::logging::log<phosphor::logging::level::ERR>(
1617 "ipmiOEMGetFscParameter: mapper error");
1618 };
James Feist09f6b602019-08-08 11:30:03 -07001619 auto config =
1620 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1621 return pair.first.find(name) != std::string::npos;
1622 });
James Feistfaa4f222019-03-21 16:21:55 -07001623 if (config != resp.end())
1624 {
1625 path = std::move(config->first);
1626 }
1627 return path;
1628}
James Feist5f957ca2019-03-14 15:33:55 -07001629
James Feistacc8a4e2019-04-02 14:23:57 -07001630// flat map to make alphabetical
1631static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1632{
1633 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001634 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001635 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001636 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1637 "/xyz/openbmc_project/object_mapper",
1638 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001639
1640 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1641 GetSubTreeType resp;
1642
1643 try
1644 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001645 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001646 reply.read(resp);
1647 }
1648 catch (sdbusplus::exception_t&)
1649 {
1650 phosphor::logging::log<phosphor::logging::level::ERR>(
1651 "getFanConfigPaths: mapper error");
1652 };
1653 for (const auto& [path, objects] : resp)
1654 {
1655 if (objects.empty())
1656 {
1657 continue; // should be impossible
1658 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001659
1660 try
1661 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001662 ret.emplace(path,
1663 getAllDbusProperties(*dbus, objects[0].first, path,
1664 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001665 }
1666 catch (sdbusplus::exception_t& e)
1667 {
1668 phosphor::logging::log<phosphor::logging::level::ERR>(
1669 "getPidConfigs: can't get DbusProperties!",
1670 phosphor::logging::entry("ERR=%s", e.what()));
1671 }
James Feistacc8a4e2019-04-02 14:23:57 -07001672 }
1673 return ret;
1674}
1675
1676ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1677{
1678 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1679 if (data.empty())
1680 {
1681 return ipmi::responseResponseError();
1682 }
1683 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1684 for (const auto& [_, pid] : data)
1685 {
1686 auto findClass = pid.find("Class");
1687 if (findClass == pid.end())
1688 {
1689 phosphor::logging::log<phosphor::logging::level::ERR>(
1690 "ipmiOEMGetFscParameter: found illegal pid "
1691 "configurations");
1692 return ipmi::responseResponseError();
1693 }
1694 std::string type = std::get<std::string>(findClass->second);
1695 if (type == "fan")
1696 {
1697 auto findOutLimit = pid.find("OutLimitMin");
1698 if (findOutLimit == pid.end())
1699 {
1700 phosphor::logging::log<phosphor::logging::level::ERR>(
1701 "ipmiOEMGetFscParameter: found illegal pid "
1702 "configurations");
1703 return ipmi::responseResponseError();
1704 }
1705 // get the min out of all the offsets
1706 minOffset = std::min(
1707 minOffset,
1708 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1709 }
1710 }
1711 if (minOffset == std::numeric_limits<uint8_t>::max())
1712 {
1713 phosphor::logging::log<phosphor::logging::level::ERR>(
1714 "ipmiOEMGetFscParameter: found no fan configurations!");
1715 return ipmi::responseResponseError();
1716 }
1717
1718 return ipmi::responseSuccess(minOffset);
1719}
1720
1721ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1722{
1723 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1724 if (data.empty())
1725 {
1726
1727 phosphor::logging::log<phosphor::logging::level::ERR>(
1728 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1729 return ipmi::responseResponseError();
1730 }
1731
Vernon Mauery15419dd2019-05-24 09:40:30 -07001732 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001733 bool found = false;
1734 for (const auto& [path, pid] : data)
1735 {
1736 auto findClass = pid.find("Class");
1737 if (findClass == pid.end())
1738 {
1739
1740 phosphor::logging::log<phosphor::logging::level::ERR>(
1741 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1742 "configurations");
1743 return ipmi::responseResponseError();
1744 }
1745 std::string type = std::get<std::string>(findClass->second);
1746 if (type == "fan")
1747 {
1748 auto findOutLimit = pid.find("OutLimitMin");
1749 if (findOutLimit == pid.end())
1750 {
1751
1752 phosphor::logging::log<phosphor::logging::level::ERR>(
1753 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1754 "configurations");
1755 return ipmi::responseResponseError();
1756 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001757 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001758 path, pidConfigurationIface, "OutLimitMin",
1759 static_cast<double>(offset));
1760 found = true;
1761 }
1762 }
1763 if (!found)
1764 {
1765 phosphor::logging::log<phosphor::logging::level::ERR>(
1766 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1767 return ipmi::responseResponseError();
1768 }
1769
1770 return ipmi::responseSuccess();
1771}
1772
1773ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1774 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001775{
1776 constexpr const size_t disableLimiting = 0x0;
1777
Vernon Mauery15419dd2019-05-24 09:40:30 -07001778 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001779 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001780 {
James Feist09f6b602019-08-08 11:30:03 -07001781 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001782 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001783 {
James Feist09f6b602019-08-08 11:30:03 -07001784 pathName = exitAirPathName;
1785 }
1786 else if (param1 == legacyPCHSensorNumber)
1787 {
1788 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001789 }
1790 else
1791 {
James Feistacc8a4e2019-04-02 14:23:57 -07001792 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001793 }
James Feist09f6b602019-08-08 11:30:03 -07001794 std::string path = getConfigPath(pathName);
1795 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1796 pidConfigurationIface, "SetPoint",
1797 static_cast<double>(param2));
1798 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001799 }
James Feistacc8a4e2019-04-02 14:23:57 -07001800 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001801 {
James Feistacc8a4e2019-04-02 14:23:57 -07001802 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001803
1804 // must be greater than 50 based on eps
1805 if (cfm < 50 && cfm != disableLimiting)
1806 {
James Feistacc8a4e2019-04-02 14:23:57 -07001807 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001808 }
1809
1810 try
1811 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001812 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001813 cfmLimitIface, "Limit",
1814 static_cast<double>(cfm));
1815 }
1816 catch (sdbusplus::exception_t& e)
1817 {
1818 phosphor::logging::log<phosphor::logging::level::ERR>(
1819 "ipmiOEMSetFscParameter: can't set cfm setting!",
1820 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001821 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001822 }
James Feistacc8a4e2019-04-02 14:23:57 -07001823 return ipmi::responseSuccess();
1824 }
1825 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1826 {
1827 constexpr const size_t maxDomainCount = 8;
1828 uint8_t requestedDomainMask = param1;
1829 boost::container::flat_map data = getPidConfigs();
1830 if (data.empty())
1831 {
1832
1833 phosphor::logging::log<phosphor::logging::level::ERR>(
1834 "ipmiOEMSetFscParameter: found no pid configurations!");
1835 return ipmi::responseResponseError();
1836 }
1837 size_t count = 0;
1838 for (const auto& [path, pid] : data)
1839 {
1840 auto findClass = pid.find("Class");
1841 if (findClass == pid.end())
1842 {
1843
1844 phosphor::logging::log<phosphor::logging::level::ERR>(
1845 "ipmiOEMSetFscParameter: found illegal pid "
1846 "configurations");
1847 return ipmi::responseResponseError();
1848 }
1849 std::string type = std::get<std::string>(findClass->second);
1850 if (type == "fan")
1851 {
1852 if (requestedDomainMask & (1 << count))
1853 {
1854 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001855 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001856 pidConfigurationIface, "OutLimitMax",
1857 static_cast<double>(param2));
1858 }
1859 count++;
1860 }
1861 }
1862 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001863 }
1864 else
1865 {
1866 // todo other command parts possibly
1867 // tcontrol is handled in peci now
1868 // fan speed offset not implemented yet
1869 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001870 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001871 }
1872}
1873
James Feistacc8a4e2019-04-02 14:23:57 -07001874ipmi::RspType<
1875 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1876 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001877{
James Feist09f6b602019-08-08 11:30:03 -07001878 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001879
Vernon Mauery15419dd2019-05-24 09:40:30 -07001880 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001881 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001882 {
James Feistacc8a4e2019-04-02 14:23:57 -07001883 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001884 {
James Feistacc8a4e2019-04-02 14:23:57 -07001885 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001886 }
1887
James Feist09f6b602019-08-08 11:30:03 -07001888 std::string pathName;
1889
1890 if (*param == legacyExitAirSensorNumber)
1891 {
1892 pathName = exitAirPathName;
1893 }
1894 else if (*param == legacyPCHSensorNumber)
1895 {
1896 pathName = pchPathName;
1897 }
1898 else
James Feistfaa4f222019-03-21 16:21:55 -07001899 {
James Feistacc8a4e2019-04-02 14:23:57 -07001900 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001901 }
James Feist09f6b602019-08-08 11:30:03 -07001902
1903 uint8_t setpoint = legacyDefaultSetpoint;
1904 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001905 if (path.size())
1906 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001907 Value val = ipmi::getDbusProperty(
1908 *dbus, "xyz.openbmc_project.EntityManager", path,
1909 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001910 setpoint = std::floor(std::get<double>(val) + 0.5);
1911 }
1912
1913 // old implementation used to return the "default" and current, we
1914 // don't make the default readily available so just make both the
1915 // same
James Feistfaa4f222019-03-21 16:21:55 -07001916
James Feistacc8a4e2019-04-02 14:23:57 -07001917 return ipmi::responseSuccess(
1918 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001919 }
James Feistacc8a4e2019-04-02 14:23:57 -07001920 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1921 {
1922 constexpr const size_t maxDomainCount = 8;
1923
1924 if (!param)
1925 {
1926 return ipmi::responseReqDataLenInvalid();
1927 }
1928 uint8_t requestedDomain = *param;
1929 if (requestedDomain >= maxDomainCount)
1930 {
1931 return ipmi::responseInvalidFieldRequest();
1932 }
1933
1934 boost::container::flat_map data = getPidConfigs();
1935 if (data.empty())
1936 {
1937 phosphor::logging::log<phosphor::logging::level::ERR>(
1938 "ipmiOEMGetFscParameter: found no pid configurations!");
1939 return ipmi::responseResponseError();
1940 }
1941 size_t count = 0;
1942 for (const auto& [_, pid] : data)
1943 {
1944 auto findClass = pid.find("Class");
1945 if (findClass == pid.end())
1946 {
1947 phosphor::logging::log<phosphor::logging::level::ERR>(
1948 "ipmiOEMGetFscParameter: found illegal pid "
1949 "configurations");
1950 return ipmi::responseResponseError();
1951 }
1952 std::string type = std::get<std::string>(findClass->second);
1953 if (type == "fan")
1954 {
1955 if (requestedDomain == count)
1956 {
1957 auto findOutLimit = pid.find("OutLimitMax");
1958 if (findOutLimit == pid.end())
1959 {
1960 phosphor::logging::log<phosphor::logging::level::ERR>(
1961 "ipmiOEMGetFscParameter: found illegal pid "
1962 "configurations");
1963 return ipmi::responseResponseError();
1964 }
1965
1966 return ipmi::responseSuccess(
1967 static_cast<uint8_t>(std::floor(
1968 std::get<double>(findOutLimit->second) + 0.5)));
1969 }
1970 else
1971 {
1972 count++;
1973 }
1974 }
1975 }
1976
1977 return ipmi::responseInvalidFieldRequest();
1978 }
1979 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001980 {
1981
1982 /*
1983 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001984 previous behavior didn't seem to prevent this, ignore the check for
1985 now.
James Feist5f957ca2019-03-14 15:33:55 -07001986
James Feistacc8a4e2019-04-02 14:23:57 -07001987 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001988 {
1989 phosphor::logging::log<phosphor::logging::level::ERR>(
1990 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001991 return IPMI_CC_REQ_DATA_LEN_INVALID;
1992 }
1993 */
1994 Value cfmLimit;
1995 Value cfmMaximum;
1996 try
1997 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001998 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001999 cfmLimitSettingPath, cfmLimitIface,
2000 "Limit");
2001 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002002 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07002003 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
2004 }
2005 catch (sdbusplus::exception_t& e)
2006 {
2007 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07002008 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07002009 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07002010 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07002011 }
2012
James Feistacc8a4e2019-04-02 14:23:57 -07002013 double cfmMax = std::get<double>(cfmMaximum);
2014 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07002015
James Feistacc8a4e2019-04-02 14:23:57 -07002016 cfmLim = std::floor(cfmLim + 0.5);
2017 cfmMax = std::floor(cfmMax + 0.5);
2018 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
2019 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07002020
James Feistacc8a4e2019-04-02 14:23:57 -07002021 return ipmi::responseSuccess(
2022 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07002023 }
James Feistacc8a4e2019-04-02 14:23:57 -07002024
James Feist5f957ca2019-03-14 15:33:55 -07002025 else
2026 {
2027 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07002028 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07002029 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07002030 }
2031}
2032
Cheng C Yang773703a2019-08-15 09:41:11 +08002033using crConfigVariant =
2034 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
2035
2036int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2037 const crConfigVariant& value,
2038 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2039{
2040 boost::system::error_code ec;
2041 ctx->bus->yield_method_call<void>(
James Feist28c72902019-09-16 10:34:07 -07002042 ctx->yield, ec, "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002043 "/xyz/openbmc_project/control/power_supply_redundancy",
2044 "org.freedesktop.DBus.Properties", "Set",
2045 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
2046 if (ec)
2047 {
2048 phosphor::logging::log<phosphor::logging::level::ERR>(
2049 "Failed to set dbus property to cold redundancy");
2050 return -1;
2051 }
2052
2053 return 0;
2054}
2055
2056int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
2057 crConfigVariant& value,
Yong Li19445ab2019-12-20 18:25:29 +08002058 const std::string& service = "xyz.openbmc_project.Settings",
Cheng C Yang773703a2019-08-15 09:41:11 +08002059 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
2060{
2061 boost::system::error_code ec;
2062 value = ctx->bus->yield_method_call<crConfigVariant>(
Yong Li19445ab2019-12-20 18:25:29 +08002063 ctx->yield, ec, service,
Cheng C Yang773703a2019-08-15 09:41:11 +08002064 "/xyz/openbmc_project/control/power_supply_redundancy",
2065 "org.freedesktop.DBus.Properties", "Get",
2066 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
2067 if (ec)
2068 {
2069 phosphor::logging::log<phosphor::logging::level::ERR>(
2070 "Failed to get dbus property to cold redundancy");
2071 return -1;
2072 }
2073 return 0;
2074}
2075
2076uint8_t getPSUCount(void)
2077{
2078 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2079 ipmi::Value num;
2080 try
2081 {
2082 num = ipmi::getDbusProperty(
2083 *dbus, "xyz.openbmc_project.PSURedundancy",
2084 "/xyz/openbmc_project/control/power_supply_redundancy",
2085 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
2086 }
2087 catch (sdbusplus::exception_t& e)
2088 {
2089 phosphor::logging::log<phosphor::logging::level::ERR>(
2090 "Failed to get PSUNumber property from dbus interface");
2091 return 0;
2092 }
2093 uint8_t* pNum = std::get_if<uint8_t>(&num);
2094 if (!pNum)
2095 {
2096 phosphor::logging::log<phosphor::logging::level::ERR>(
2097 "Error to get PSU Number");
2098 return 0;
2099 }
2100 return *pNum;
2101}
2102
2103bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
2104{
2105 if (conf.size() < num)
2106 {
2107 phosphor::logging::log<phosphor::logging::level::ERR>(
2108 "Invalid PSU Ranking");
2109 return false;
2110 }
2111 std::set<uint8_t> confSet;
2112 for (uint8_t i = 0; i < num; i++)
2113 {
2114 if (conf[i] > num)
2115 {
2116 phosphor::logging::log<phosphor::logging::level::ERR>(
2117 "PSU Ranking is larger than current PSU number");
2118 return false;
2119 }
2120 confSet.emplace(conf[i]);
2121 }
2122
2123 if (confSet.size() != num)
2124 {
2125 phosphor::logging::log<phosphor::logging::level::ERR>(
2126 "duplicate PSU Ranking");
2127 return false;
2128 }
2129 return true;
2130}
2131
2132enum class crParameter
2133{
2134 crStatus = 0,
2135 crFeature = 1,
2136 rotationFeature = 2,
2137 rotationAlgo = 3,
2138 rotationPeriod = 4,
Yong Li19445ab2019-12-20 18:25:29 +08002139 numOfPSU = 5,
2140 rotationRankOrderEffective = 6
Cheng C Yang773703a2019-08-15 09:41:11 +08002141};
2142
2143constexpr ipmi::Cc ccParameterNotSupported = 0x80;
2144static const constexpr uint32_t oneDay = 0x15180;
2145static const constexpr uint32_t oneMonth = 0xf53700;
2146static const constexpr uint8_t userSpecific = 0x01;
2147static const constexpr uint8_t crSetCompleted = 0;
2148ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
2149 uint8_t parameter,
2150 ipmi::message::Payload& payload)
2151{
2152 switch (static_cast<crParameter>(parameter))
2153 {
2154 case crParameter::crFeature:
2155 {
2156 uint8_t param1;
2157 if (payload.unpack(param1) || !payload.fullyUnpacked())
2158 {
2159 return ipmi::responseReqDataLenInvalid();
2160 }
2161 // ColdRedundancy Enable can only be true or flase
2162 if (param1 > 1)
2163 {
2164 return ipmi::responseInvalidFieldRequest();
2165 }
2166 if (setCRConfig(ctx, "ColdRedundancyEnabled",
2167 static_cast<bool>(param1)))
2168 {
2169 return ipmi::responseResponseError();
2170 }
2171 break;
2172 }
2173 case crParameter::rotationFeature:
2174 {
2175 uint8_t param1;
2176 if (payload.unpack(param1) || !payload.fullyUnpacked())
2177 {
2178 return ipmi::responseReqDataLenInvalid();
2179 }
2180 // Rotation Enable can only be true or false
2181 if (param1 > 1)
2182 {
2183 return ipmi::responseInvalidFieldRequest();
2184 }
2185 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
2186 {
2187 return ipmi::responseResponseError();
2188 }
2189 break;
2190 }
2191 case crParameter::rotationAlgo:
2192 {
2193 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
2194 std::string algoName;
2195 uint8_t param1;
2196 if (payload.unpack(param1))
2197 {
2198 return ipmi::responseReqDataLenInvalid();
2199 }
2200 switch (param1)
2201 {
2202 case 0:
2203 algoName = "xyz.openbmc_project.Control."
2204 "PowerSupplyRedundancy.Algo.bmcSpecific";
2205 break;
2206 case 1:
2207 algoName = "xyz.openbmc_project.Control."
2208 "PowerSupplyRedundancy.Algo.userSpecific";
2209 break;
2210 default:
2211 return ipmi::responseInvalidFieldRequest();
2212 }
2213 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
2214 {
2215 return ipmi::responseResponseError();
2216 }
2217
2218 uint8_t numberOfPSU = getPSUCount();
2219 if (!numberOfPSU)
2220 {
2221 return ipmi::responseResponseError();
2222 }
2223 std::vector<uint8_t> rankOrder;
2224
2225 if (param1 == userSpecific)
2226 {
2227 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2228 {
2229 ipmi::responseReqDataLenInvalid();
2230 }
Yong Li83315132019-10-23 17:42:24 +08002231 if (rankOrder.size() != numberOfPSU)
Cheng C Yang773703a2019-08-15 09:41:11 +08002232 {
2233 return ipmi::responseReqDataLenInvalid();
2234 }
2235
2236 if (!validateCRAlgo(rankOrder, numberOfPSU))
2237 {
2238 return ipmi::responseInvalidFieldRequest();
2239 }
2240 }
2241 else
2242 {
2243 if (rankOrder.size() > 0)
2244 {
2245 return ipmi::responseReqDataLenInvalid();
2246 }
2247 for (uint8_t i = 1; i <= numberOfPSU; i++)
2248 {
2249 rankOrder.emplace_back(i);
2250 }
2251 }
2252 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2253 {
2254 return ipmi::responseResponseError();
2255 }
2256 break;
2257 }
2258 case crParameter::rotationPeriod:
2259 {
2260 // Minimum Rotation period is One day (86400 seconds) and Max
2261 // Rotation Period is 6 month (0xf53700 seconds)
2262 uint32_t period;
2263 if (payload.unpack(period) || !payload.fullyUnpacked())
2264 {
2265 return ipmi::responseReqDataLenInvalid();
2266 }
2267 if ((period < oneDay) || (period > oneMonth))
2268 {
2269 return ipmi::responseInvalidFieldRequest();
2270 }
2271 if (setCRConfig(ctx, "PeriodOfRotation", period))
2272 {
2273 return ipmi::responseResponseError();
2274 }
2275 break;
2276 }
2277 default:
2278 {
2279 return ipmi::response(ccParameterNotSupported);
2280 }
2281 }
2282
2283 // TODO Halfwidth needs to set SetInProgress
2284 if (setCRConfig(ctx, "ColdRedundancyStatus",
Cheng C Yange8cecdf2019-08-26 23:48:08 +08002285 std::string("xyz.openbmc_project.Control."
2286 "PowerSupplyRedundancy.Status.completed")))
Cheng C Yang773703a2019-08-15 09:41:11 +08002287 {
2288 return ipmi::responseResponseError();
2289 }
2290 return ipmi::responseSuccess(crSetCompleted);
2291}
2292
Yong Li83315132019-10-23 17:42:24 +08002293ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>>
Cheng C Yang773703a2019-08-15 09:41:11 +08002294 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2295{
2296 crConfigVariant value;
2297 switch (static_cast<crParameter>(parameter))
2298 {
2299 case crParameter::crStatus:
2300 {
2301 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2302 {
2303 return ipmi::responseResponseError();
2304 }
2305 std::string* pStatus = std::get_if<std::string>(&value);
2306 if (!pStatus)
2307 {
2308 phosphor::logging::log<phosphor::logging::level::ERR>(
2309 "Error to get ColdRedundancyStatus property");
2310 return ipmi::responseResponseError();
2311 }
2312 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2313 auto status =
2314 server::PowerSupplyRedundancy::convertStatusFromString(
2315 *pStatus);
2316 switch (status)
2317 {
2318 case server::PowerSupplyRedundancy::Status::inProgress:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002319 return ipmi::responseSuccess(parameter,
2320 static_cast<uint8_t>(0));
Cheng C Yang773703a2019-08-15 09:41:11 +08002321
2322 case server::PowerSupplyRedundancy::Status::completed:
Cheng C Yangf41e3342019-09-10 04:47:23 +08002323 return ipmi::responseSuccess(parameter,
2324 static_cast<uint8_t>(1));
Cheng C Yang773703a2019-08-15 09:41:11 +08002325 default:
2326 phosphor::logging::log<phosphor::logging::level::ERR>(
2327 "Error to get valid status");
2328 return ipmi::responseResponseError();
2329 }
2330 }
2331 case crParameter::crFeature:
2332 {
2333 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2334 {
2335 return ipmi::responseResponseError();
2336 }
2337 bool* pResponse = std::get_if<bool>(&value);
2338 if (!pResponse)
2339 {
2340 phosphor::logging::log<phosphor::logging::level::ERR>(
2341 "Error to get ColdRedundancyEnable property");
2342 return ipmi::responseResponseError();
2343 }
2344
Cheng C Yangf41e3342019-09-10 04:47:23 +08002345 return ipmi::responseSuccess(parameter,
2346 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002347 }
2348 case crParameter::rotationFeature:
2349 {
2350 if (getCRConfig(ctx, "RotationEnabled", value))
2351 {
2352 return ipmi::responseResponseError();
2353 }
2354 bool* pResponse = std::get_if<bool>(&value);
2355 if (!pResponse)
2356 {
2357 phosphor::logging::log<phosphor::logging::level::ERR>(
2358 "Error to get RotationEnabled property");
2359 return ipmi::responseResponseError();
2360 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002361 return ipmi::responseSuccess(parameter,
2362 static_cast<uint8_t>(*pResponse));
Cheng C Yang773703a2019-08-15 09:41:11 +08002363 }
2364 case crParameter::rotationAlgo:
2365 {
2366 if (getCRConfig(ctx, "RotationAlgorithm", value))
2367 {
2368 return ipmi::responseResponseError();
2369 }
2370
2371 std::string* pAlgo = std::get_if<std::string>(&value);
2372 if (!pAlgo)
2373 {
2374 phosphor::logging::log<phosphor::logging::level::ERR>(
2375 "Error to get RotationAlgorithm property");
2376 return ipmi::responseResponseError();
2377 }
Yong Li83315132019-10-23 17:42:24 +08002378 std::vector<uint8_t> response;
Cheng C Yang773703a2019-08-15 09:41:11 +08002379 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2380 auto algo =
2381 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
Yong Li83315132019-10-23 17:42:24 +08002382
Cheng C Yang773703a2019-08-15 09:41:11 +08002383 switch (algo)
2384 {
2385 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
Yong Li83315132019-10-23 17:42:24 +08002386 response.push_back(0);
Cheng C Yang773703a2019-08-15 09:41:11 +08002387 break;
2388 case server::PowerSupplyRedundancy::Algo::userSpecific:
Yong Li83315132019-10-23 17:42:24 +08002389 response.push_back(1);
Cheng C Yang773703a2019-08-15 09:41:11 +08002390 break;
2391 default:
2392 phosphor::logging::log<phosphor::logging::level::ERR>(
2393 "Error to get valid algo");
2394 return ipmi::responseResponseError();
2395 }
2396
2397 if (getCRConfig(ctx, "RotationRankOrder", value))
2398 {
2399 return ipmi::responseResponseError();
2400 }
2401 std::vector<uint8_t>* pResponse =
2402 std::get_if<std::vector<uint8_t>>(&value);
2403 if (!pResponse)
2404 {
2405 phosphor::logging::log<phosphor::logging::level::ERR>(
2406 "Error to get RotationRankOrder property");
2407 return ipmi::responseResponseError();
2408 }
Yong Li83315132019-10-23 17:42:24 +08002409
Cheng C Yang773703a2019-08-15 09:41:11 +08002410 std::copy(pResponse->begin(), pResponse->end(),
Yong Li83315132019-10-23 17:42:24 +08002411 std::back_inserter(response));
2412
Cheng C Yangf41e3342019-09-10 04:47:23 +08002413 return ipmi::responseSuccess(parameter, response);
Cheng C Yang773703a2019-08-15 09:41:11 +08002414 }
2415 case crParameter::rotationPeriod:
2416 {
2417 if (getCRConfig(ctx, "PeriodOfRotation", value))
2418 {
2419 return ipmi::responseResponseError();
2420 }
2421 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2422 if (!pResponse)
2423 {
2424 phosphor::logging::log<phosphor::logging::level::ERR>(
2425 "Error to get RotationAlgorithm property");
2426 return ipmi::responseResponseError();
2427 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002428 return ipmi::responseSuccess(parameter, *pResponse);
Cheng C Yang773703a2019-08-15 09:41:11 +08002429 }
2430 case crParameter::numOfPSU:
2431 {
2432 uint8_t numberOfPSU = getPSUCount();
2433 if (!numberOfPSU)
2434 {
2435 return ipmi::responseResponseError();
2436 }
Cheng C Yangf41e3342019-09-10 04:47:23 +08002437 return ipmi::responseSuccess(parameter, numberOfPSU);
Cheng C Yang773703a2019-08-15 09:41:11 +08002438 }
Yong Li19445ab2019-12-20 18:25:29 +08002439 case crParameter::rotationRankOrderEffective:
2440 {
2441 if (getCRConfig(ctx, "RotationRankOrder", value,
2442 "xyz.openbmc_project.PSURedundancy"))
2443 {
2444 return ipmi::responseResponseError();
2445 }
2446 std::vector<uint8_t>* pResponse =
2447 std::get_if<std::vector<uint8_t>>(&value);
2448 if (!pResponse)
2449 {
2450 phosphor::logging::log<phosphor::logging::level::ERR>(
2451 "Error to get effective RotationRankOrder property");
2452 return ipmi::responseResponseError();
2453 }
2454 return ipmi::responseSuccess(parameter, *pResponse);
2455 }
Cheng C Yang773703a2019-08-15 09:41:11 +08002456 default:
2457 {
2458 return ipmi::response(ccParameterNotSupported);
2459 }
2460 }
2461}
2462
Zhu, Yungebe560b02019-04-21 21:19:21 -04002463ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2464 uint8_t faultState,
2465 uint8_t faultGroup,
2466 std::array<uint8_t, 8>& ledStateData)
2467{
Zhu, Yungebe560b02019-04-21 21:19:21 -04002468 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2469 static const std::array<std::string, maxFaultType> faultNames = {
2470 "faultFan", "faultTemp", "faultPower",
2471 "faultDriveSlot", "faultSoftware", "faultMemory"};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002472
2473 constexpr uint8_t maxFaultSource = 0x4;
2474 constexpr uint8_t skipLEDs = 0xFF;
2475 constexpr uint8_t pinSize = 64;
2476 constexpr uint8_t groupSize = 16;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002477 constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan
Zhu, Yungebe560b02019-04-21 21:19:21 -04002478
Zhikui Rence4e73f2019-12-06 13:59:47 -08002479 // same pin names need to be defined in dts file
2480 static const std::array<std::array<std::string, groupSize>, groupNum>
2481 faultLedPinNames = {{
2482 "LED_CPU1_CH1_DIMM1_FAULT",
2483 "LED_CPU1_CH1_DIMM2_FAULT",
2484 "LED_CPU1_CH2_DIMM1_FAULT",
2485 "LED_CPU1_CH2_DIMM2_FAULT",
2486 "LED_CPU1_CH3_DIMM1_FAULT",
2487 "LED_CPU1_CH3_DIMM2_FAULT",
2488 "LED_CPU1_CH4_DIMM1_FAULT",
2489 "LED_CPU1_CH4_DIMM2_FAULT",
2490 "LED_CPU1_CH5_DIMM1_FAULT",
2491 "LED_CPU1_CH5_DIMM2_FAULT",
2492 "LED_CPU1_CH6_DIMM1_FAULT",
2493 "LED_CPU1_CH6_DIMM2_FAULT",
2494 "",
2495 "",
2496 "",
2497 "", // end of group1
2498 "LED_CPU2_CH1_DIMM1_FAULT",
2499 "LED_CPU2_CH1_DIMM2_FAULT",
2500 "LED_CPU2_CH2_DIMM1_FAULT",
2501 "LED_CPU2_CH2_DIMM2_FAULT",
2502 "LED_CPU2_CH3_DIMM1_FAULT",
2503 "LED_CPU2_CH3_DIMM2_FAULT",
2504 "LED_CPU2_CH4_DIMM1_FAULT",
2505 "LED_CPU2_CH4_DIMM2_FAULT",
2506 "LED_CPU2_CH5_DIMM1_FAULT",
2507 "LED_CPU2_CH5_DIMM2_FAULT",
2508 "LED_CPU2_CH6_DIMM1_FAULT",
2509 "LED_CPU2_CH6_DIMM2_FAULT",
2510 "",
2511 "",
2512 "",
2513 "", // endof group2
2514 "LED_CPU3_CH1_DIMM1_FAULT",
2515 "LED_CPU3_CH1_DIMM2_FAULT",
2516 "LED_CPU3_CH2_DIMM1_FAULT",
2517 "LED_CPU3_CH2_DIMM2_FAULT",
2518 "LED_CPU3_CH3_DIMM1_FAULT",
2519 "LED_CPU3_CH3_DIMM2_FAULT",
2520 "LED_CPU3_CH4_DIMM1_FAULT",
2521 "LED_CPU3_CH4_DIMM2_FAULT",
2522 "LED_CPU3_CH5_DIMM1_FAULT",
2523 "LED_CPU3_CH5_DIMM2_FAULT",
2524 "LED_CPU3_CH6_DIMM1_FAULT",
2525 "LED_CPU3_CH6_DIMM2_FAULT",
2526 "",
2527 "",
2528 "",
2529 "", // end of group3
2530 "LED_CPU4_CH1_DIMM1_FAULT",
2531 "LED_CPU4_CH1_DIMM2_FAULT",
2532 "LED_CPU4_CH2_DIMM1_FAULT",
2533 "LED_CPU4_CH2_DIMM2_FAULT",
2534 "LED_CPU4_CH3_DIMM1_FAULT",
2535 "LED_CPU4_CH3_DIMM2_FAULT",
2536 "LED_CPU4_CH4_DIMM1_FAULT",
2537 "LED_CPU4_CH4_DIMM2_FAULT",
2538 "LED_CPU4_CH5_DIMM1_FAULT",
2539 "LED_CPU4_CH5_DIMM2_FAULT",
2540 "LED_CPU4_CH6_DIMM1_FAULT",
2541 "LED_CPU4_CH6_DIMM2_FAULT",
2542 "",
2543 "",
2544 "",
2545 "", // end of group4
2546 "LED_FAN1_FAULT",
2547 "LED_FAN2_FAULT",
2548 "LED_FAN3_FAULT",
2549 "LED_FAN4_FAULT",
2550 "LED_FAN5_FAULT",
2551 "LED_FAN6_FAULT",
2552 "LED_FAN7_FAULT",
2553 "LED_FAN8_FAULT",
2554 "",
2555 "",
2556 "",
2557 "",
2558 "",
2559 "",
2560 "",
2561 "" // end of group5
2562 }};
Zhu, Yungebe560b02019-04-21 21:19:21 -04002563
Zhikui Rence4e73f2019-12-06 13:59:47 -08002564 // Validate the source, fault type --
2565 // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap
2566 // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power,
2567 // driveslot, software, memory (Byte 3) FaultState: OK, Degraded,
2568 // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup,
2569 // definition differs based on fault type (Byte 2)
2570 // Type Fan=> Group: 0=FanGroupID, FF-not used
2571 // Byte 5-11 00h, not used
2572 // Byte12 FanLedState [7:0]-Fans 7:0
2573 // Type Memory=> Group: 0 = DIMM GroupID, FF-not used
2574 // Byte 5:12 - DIMM LED state (64bit field, LS Byte first)
2575 // [63:48] = CPU4 channels 7:0, 2 bits per channel
2576 // [47:32] = CPU3 channels 7:0, 2 bits per channel
2577 // [31:16] = CPU2 channels 7:0, 2 bits per channel
2578 // [15:0] = CPU1 channels 7:0, 2 bits per channel
2579 // Type Other=> Component Fault LED Group ID, not used set to 0xFF
2580 // Byte[5:12]: reserved 0x00h
Zhu, Yungebe560b02019-04-21 21:19:21 -04002581 if ((sourceId >= maxFaultSource) ||
2582 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2583 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2584 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2585 {
2586 return ipmi::responseParmOutOfRange();
2587 }
2588
Zhikui Rence4e73f2019-12-06 13:59:47 -08002589 size_t pinGroupOffset = 0;
2590 size_t pinGroupMax = pinSize / groupSize;
2591 if (RemoteFaultType::fan == RemoteFaultType(faultType))
Zhu, Yungebe560b02019-04-21 21:19:21 -04002592 {
Zhikui Rence4e73f2019-12-06 13:59:47 -08002593 pinGroupOffset = 4;
2594 pinGroupMax = groupNum - pinSize / groupSize;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002595 }
2596
2597 switch (RemoteFaultType(faultType))
2598 {
2599 case (RemoteFaultType::fan):
2600 case (RemoteFaultType::memory):
2601 {
2602 if (faultGroup == skipLEDs)
2603 {
2604 return ipmi::responseSuccess();
2605 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002606 // calculate led state bit filed count, each byte has 8bits
2607 // the maximum bits will be 8 * 8 bits
2608 constexpr uint8_t size = sizeof(ledStateData) * 8;
Zhikui Rence4e73f2019-12-06 13:59:47 -08002609
2610 // assemble ledState
2611 uint64_t ledState = 0;
2612 bool hasError = false;
Zhu, Yungebe560b02019-04-21 21:19:21 -04002613 for (int i = 0; i < sizeof(ledStateData); i++)
2614 {
2615 ledState = (uint64_t)(ledState << 8);
2616 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2617 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002618 std::bitset<size> ledStateBits(ledState);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002619
Zhikui Rence4e73f2019-12-06 13:59:47 -08002620 for (int group = 0; group < pinGroupMax; group++)
2621 {
2622 for (int i = 0; i < groupSize; i++)
2623 { // skip non-existing pins
2624 if (0 == faultLedPinNames[group + pinGroupOffset][i].size())
2625 {
2626 continue;
2627 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002628
Zhikui Rence4e73f2019-12-06 13:59:47 -08002629 gpiod::line line = gpiod::find_line(
2630 faultLedPinNames[group + pinGroupOffset][i]);
2631 if (!line)
2632 {
2633 phosphor::logging::log<phosphor::logging::level::ERR>(
2634 "Not Find Led Gpio Device!",
2635 phosphor::logging::entry(
2636 "DEVICE=%s",
2637 faultLedPinNames[group + pinGroupOffset][i]
2638 .c_str()));
2639 hasError = true;
2640 continue;
2641 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04002642
Zhikui Rence4e73f2019-12-06 13:59:47 -08002643 bool activeHigh =
2644 (line.active_state() == gpiod::line::ACTIVE_HIGH);
2645 try
2646 {
2647 line.request(
2648 {"faultLed", gpiod::line_request::DIRECTION_OUTPUT,
2649 activeHigh
2650 ? 0
2651 : gpiod::line_request::FLAG_ACTIVE_LOW});
2652 line.set_value(ledStateBits[i + group * groupSize]);
2653 }
2654 catch (std::system_error&)
2655 {
2656 phosphor::logging::log<phosphor::logging::level::ERR>(
2657 "Error write Led Gpio Device!",
2658 phosphor::logging::entry(
2659 "DEVICE=%s",
2660 faultLedPinNames[group + pinGroupOffset][i]
2661 .c_str()));
2662 hasError = true;
2663 continue;
2664 }
2665 } // for int i
2666 }
2667 if (hasError)
2668 {
2669 return ipmi::responseResponseError();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002670 }
2671 break;
2672 }
2673 default:
2674 {
2675 // now only support two fault types
2676 return ipmi::responseParmOutOfRange();
2677 }
Zhikui Rence4e73f2019-12-06 13:59:47 -08002678 } // switch
Zhu, Yungebe560b02019-04-21 21:19:21 -04002679 return ipmi::responseSuccess();
2680}
2681
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302682ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2683{
2684 uint8_t prodId = 0;
2685 try
2686 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002687 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302688 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002689 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302690 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2691 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002692 *dbus, object.second, object.first,
Suryakanth Sekar6c57e5c2020-01-10 17:11:58 +05302693 "xyz.openbmc_project.Inventory.Item.Board.Motherboard",
2694 "ProductId");
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302695 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2696 }
2697 catch (std::exception& e)
2698 {
2699 phosphor::logging::log<phosphor::logging::level::ERR>(
2700 "ipmiOEMReadBoardProductId: Product ID read failed!",
2701 phosphor::logging::entry("ERR=%s", e.what()));
2702 }
2703 return ipmi::responseSuccess(prodId);
2704}
2705
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302706/** @brief implements the get security mode command
2707 * @param ctx - ctx pointer
2708 *
2709 * @returns IPMI completion code with following data
2710 * - restriction mode value - As specified in
2711 * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml
2712 * - special mode value - As specified in
2713 * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml
2714 */
2715ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx)
2716{
2717 namespace securityNameSpace =
2718 sdbusplus::xyz::openbmc_project::Control::Security::server;
2719 uint8_t restrictionModeValue = 0;
2720 uint8_t specialModeValue = 0;
2721
2722 boost::system::error_code ec;
2723 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002724 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302725 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2726 restricionModeProperty);
2727 if (ec)
2728 {
2729 phosphor::logging::log<phosphor::logging::level::ERR>(
2730 "ipmiGetSecurityMode: failed to get RestrictionMode property",
2731 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2732 return ipmi::responseUnspecifiedError();
2733 }
2734 restrictionModeValue = static_cast<uint8_t>(
2735 securityNameSpace::RestrictionMode::convertModesFromString(
2736 std::get<std::string>(varRestrMode)));
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302737 auto varSpecialMode =
2738 ctx->bus->yield_method_call<std::variant<std::string>>(
2739 ctx->yield, ec, specialModeService, specialModeBasePath,
2740 dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf,
2741 specialModeProperty);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302742 if (ec)
2743 {
2744 phosphor::logging::log<phosphor::logging::level::ERR>(
2745 "ipmiGetSecurityMode: failed to get SpecialMode property",
2746 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2747 // fall through, let us not worry about SpecialMode property, which is
2748 // not required in user scenario
2749 }
2750 else
2751 {
Richard Marian Thomaiyar8d4f8d72019-11-11 12:06:40 +05302752 specialModeValue = static_cast<uint8_t>(
2753 securityNameSpace::SpecialMode::convertModesFromString(
2754 std::get<std::string>(varSpecialMode)));
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302755 }
2756 return ipmi::responseSuccess(restrictionModeValue, specialModeValue);
2757}
2758
2759/** @brief implements the set security mode command
2760 * Command allows to upgrade the restriction mode and won't allow
2761 * to downgrade from system interface
2762 * @param ctx - ctx pointer
2763 * @param restrictionMode - restriction mode value to be set.
2764 *
2765 * @returns IPMI completion code
2766 */
2767ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx,
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302768 uint8_t restrictionMode,
2769 std::optional<uint8_t> specialMode)
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302770{
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302771#ifndef BMC_VALIDATION_UNSECURE_FEATURE
2772 if (specialMode)
2773 {
2774 return ipmi::responseReqDataLenInvalid();
2775 }
2776#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302777 namespace securityNameSpace =
2778 sdbusplus::xyz::openbmc_project::Control::Security::server;
2779
2780 ChannelInfo chInfo;
2781 if (getChannelInfo(ctx->channel, chInfo) != ccSuccess)
2782 {
2783 phosphor::logging::log<phosphor::logging::level::ERR>(
2784 "ipmiSetSecurityMode: Failed to get Channel Info",
2785 phosphor::logging::entry("CHANNEL=%d", ctx->channel));
2786 return ipmi::responseUnspecifiedError();
2787 }
2788 auto reqMode =
2789 static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode);
2790
2791 if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) ||
2792 (reqMode >
2793 securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled))
2794 {
2795 return ipmi::responseInvalidFieldRequest();
2796 }
2797
2798 boost::system::error_code ec;
2799 auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>(
James Feist28c72902019-09-16 10:34:07 -07002800 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302801 dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf,
2802 restricionModeProperty);
2803 if (ec)
2804 {
2805 phosphor::logging::log<phosphor::logging::level::ERR>(
2806 "ipmiSetSecurityMode: failed to get RestrictionMode property",
2807 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2808 return ipmi::responseUnspecifiedError();
2809 }
2810 auto currentRestrictionMode =
2811 securityNameSpace::RestrictionMode::convertModesFromString(
2812 std::get<std::string>(varRestrMode));
2813
2814 if (chInfo.mediumType !=
2815 static_cast<uint8_t>(EChannelMediumType::lan8032) &&
2816 currentRestrictionMode > reqMode)
2817 {
2818 phosphor::logging::log<phosphor::logging::level::ERR>(
2819 "ipmiSetSecurityMode - Downgrading security mode not supported "
2820 "through system interface",
2821 phosphor::logging::entry(
2822 "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)),
2823 phosphor::logging::entry("REQ_MODE=%d", restrictionMode));
2824 return ipmi::responseCommandNotAvailable();
2825 }
2826
2827 ec.clear();
2828 ctx->bus->yield_method_call<>(
James Feist28c72902019-09-16 10:34:07 -07002829 ctx->yield, ec, restricionModeService, restricionModeBasePath,
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302830 dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf,
2831 restricionModeProperty,
2832 static_cast<std::variant<std::string>>(
2833 securityNameSpace::convertForMessage(reqMode)));
2834
2835 if (ec)
2836 {
2837 phosphor::logging::log<phosphor::logging::level::ERR>(
2838 "ipmiSetSecurityMode: failed to set RestrictionMode property",
2839 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2840 return ipmi::responseUnspecifiedError();
2841 }
Richard Marian Thomaiyar10791062019-11-11 12:19:53 +05302842
2843#ifdef BMC_VALIDATION_UNSECURE_FEATURE
2844 if (specialMode)
2845 {
2846 ec.clear();
2847 ctx->bus->yield_method_call<>(
2848 ctx->yield, ec, specialModeService, specialModeBasePath,
2849 dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf,
2850 specialModeProperty,
2851 static_cast<std::variant<std::string>>(
2852 securityNameSpace::convertForMessage(
2853 static_cast<securityNameSpace::SpecialMode::Modes>(
2854 specialMode.value()))));
2855
2856 if (ec)
2857 {
2858 phosphor::logging::log<phosphor::logging::level::ERR>(
2859 "ipmiSetSecurityMode: failed to set SpecialMode property",
2860 phosphor::logging::entry("ERROR=%s", ec.message().c_str()));
2861 return ipmi::responseUnspecifiedError();
2862 }
2863 }
2864#endif
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05302865 return ipmi::responseSuccess();
2866}
2867
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002868ipmi::RspType<uint8_t /* restore status */>
2869 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2870{
2871 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2872
2873 if (clr != expClr)
2874 {
2875 return ipmi::responseInvalidFieldRequest();
2876 }
2877 constexpr uint8_t cmdStatus = 0;
2878 constexpr uint8_t cmdDefaultRestore = 0xaa;
2879 constexpr uint8_t cmdFullRestore = 0xbb;
2880 constexpr uint8_t cmdFormat = 0xcc;
2881
2882 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2883
2884 switch (cmd)
2885 {
2886 case cmdStatus:
2887 break;
2888 case cmdDefaultRestore:
2889 case cmdFullRestore:
2890 case cmdFormat:
2891 {
2892 // write file to rwfs root
2893 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2894 std::ofstream restoreFile(restoreOpFname);
2895 if (!restoreFile)
2896 {
2897 return ipmi::responseUnspecifiedError();
2898 }
2899 restoreFile << value << "\n";
2900 break;
2901 }
2902 default:
2903 return ipmi::responseInvalidFieldRequest();
2904 }
2905
2906 constexpr uint8_t restorePending = 0;
2907 constexpr uint8_t restoreComplete = 1;
2908
2909 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2910 ? restorePending
2911 : restoreComplete;
2912 return ipmi::responseSuccess(restoreStatus);
2913}
2914
Chen Yugang39736d52019-07-12 16:24:33 +08002915ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2916{
2917 uint8_t bmcSource;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002918 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002919
2920 try
2921 {
2922 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2923 std::string service =
2924 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2925 Value variant =
2926 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2927 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2928
2929 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2930 std::get<std::string>(variant)))
2931 {
2932 case nmi::NMISource::BMCSourceSignal::None:
2933 bmcSource = static_cast<uint8_t>(NmiSource::none);
2934 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002935 case nmi::NMISource::BMCSourceSignal::FrontPanelButton:
2936 bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton);
Chen Yugang39736d52019-07-12 16:24:33 +08002937 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002938 case nmi::NMISource::BMCSourceSignal::Watchdog:
2939 bmcSource = static_cast<uint8_t>(NmiSource::watchdog);
Chen Yugang39736d52019-07-12 16:24:33 +08002940 break;
2941 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2942 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2943 break;
2944 case nmi::NMISource::BMCSourceSignal::MemoryError:
2945 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2946 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002947 case nmi::NMISource::BMCSourceSignal::PciBusError:
2948 bmcSource = static_cast<uint8_t>(NmiSource::pciBusError);
Chen Yugang39736d52019-07-12 16:24:33 +08002949 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002950 case nmi::NMISource::BMCSourceSignal::PCH:
2951 bmcSource = static_cast<uint8_t>(NmiSource::pch);
Chen Yugang39736d52019-07-12 16:24:33 +08002952 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002953 case nmi::NMISource::BMCSourceSignal::Chipset:
2954 bmcSource = static_cast<uint8_t>(NmiSource::chipset);
Chen Yugang39736d52019-07-12 16:24:33 +08002955 break;
2956 default:
2957 phosphor::logging::log<phosphor::logging::level::ERR>(
2958 "NMI source: invalid property!",
2959 phosphor::logging::entry(
2960 "PROP=%s", std::get<std::string>(variant).c_str()));
2961 return ipmi::responseResponseError();
2962 }
2963 }
2964 catch (sdbusplus::exception::SdBusError& e)
2965 {
2966 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2967 return ipmi::responseResponseError();
2968 }
2969
2970 return ipmi::responseSuccess(bmcSource);
2971}
2972
2973ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2974{
Chen Yugang97cf96e2019-11-01 08:55:11 +08002975 namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server;
Chen Yugang39736d52019-07-12 16:24:33 +08002976
2977 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2978 nmi::NMISource::BMCSourceSignal::None;
2979
2980 switch (NmiSource(sourceId))
2981 {
2982 case NmiSource::none:
2983 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2984 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002985 case NmiSource::frontPanelButton:
2986 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton;
Chen Yugang39736d52019-07-12 16:24:33 +08002987 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002988 case NmiSource::watchdog:
2989 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog;
Chen Yugang39736d52019-07-12 16:24:33 +08002990 break;
2991 case NmiSource::chassisCmd:
2992 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2993 break;
2994 case NmiSource::memoryError:
2995 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2996 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08002997 case NmiSource::pciBusError:
2998 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError;
Chen Yugang39736d52019-07-12 16:24:33 +08002999 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003000 case NmiSource::pch:
3001 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH;
Chen Yugang39736d52019-07-12 16:24:33 +08003002 break;
Chen Yugang97cf96e2019-11-01 08:55:11 +08003003 case NmiSource::chipset:
3004 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset;
Chen Yugang39736d52019-07-12 16:24:33 +08003005 break;
3006 default:
3007 phosphor::logging::log<phosphor::logging::level::ERR>(
3008 "NMI source: invalid property!");
3009 return ipmi::responseResponseError();
3010 }
3011
3012 try
3013 {
3014 // keep NMI signal source
3015 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3016 std::string service =
3017 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
Chen Yugang97cf96e2019-11-01 08:55:11 +08003018 setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
3019 oemNmiBmcSourceObjPathProp,
3020 nmi::convertForMessage(bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08003021 // set Enabled property to inform NMI source handling
3022 // to trigger a NMI_OUT BSOD.
3023 // if it's triggered by NMI source property changed,
3024 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
3025 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
3026 {
3027 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
3028 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
3029 static_cast<bool>(true));
3030 }
Chen Yugang39736d52019-07-12 16:24:33 +08003031 }
3032 catch (sdbusplus::exception_t& e)
3033 {
3034 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3035 return ipmi::responseResponseError();
3036 }
3037
3038 return ipmi::responseSuccess();
3039}
3040
James Feist63efafa2019-07-24 12:39:21 -07003041namespace dimmOffset
3042{
3043constexpr const char* dimmPower = "DimmPower";
3044constexpr const char* staticCltt = "StaticCltt";
3045constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
3046constexpr const char* offsetInterface =
3047 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
3048constexpr const char* property = "DimmOffset";
3049
3050}; // namespace dimmOffset
3051
3052ipmi::RspType<>
3053 ipmiOEMSetDimmOffset(uint8_t type,
3054 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
3055{
3056 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3057 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3058 {
3059 return ipmi::responseInvalidFieldRequest();
3060 }
3061
3062 if (data.empty())
3063 {
3064 return ipmi::responseInvalidFieldRequest();
3065 }
3066 nlohmann::json json;
3067
3068 std::ifstream jsonStream(dimmOffsetFile);
3069 if (jsonStream.good())
3070 {
3071 json = nlohmann::json::parse(jsonStream, nullptr, false);
3072 if (json.is_discarded())
3073 {
3074 json = nlohmann::json();
3075 }
3076 jsonStream.close();
3077 }
3078
3079 std::string typeName;
3080 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3081 {
3082 typeName = dimmOffset::dimmPower;
3083 }
3084 else
3085 {
3086 typeName = dimmOffset::staticCltt;
3087 }
3088
3089 nlohmann::json& field = json[typeName];
3090
3091 for (const auto& [index, value] : data)
3092 {
3093 field[index] = value;
3094 }
3095
3096 for (nlohmann::json& val : field)
3097 {
3098 if (val == nullptr)
3099 {
3100 val = static_cast<uint8_t>(0);
3101 }
3102 }
3103
3104 std::ofstream output(dimmOffsetFile);
3105 if (!output.good())
3106 {
3107 std::cerr << "Error writing json file\n";
3108 return ipmi::responseResponseError();
3109 }
3110
3111 output << json.dump(4);
3112
3113 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3114 {
3115 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
3116
3117 std::variant<std::vector<uint8_t>> offsets =
3118 field.get<std::vector<uint8_t>>();
3119 auto call = bus->new_method_call(
3120 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
3121 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
3122 try
3123 {
3124 bus->call(call);
3125 }
3126 catch (sdbusplus::exception_t& e)
3127 {
3128 phosphor::logging::log<phosphor::logging::level::ERR>(
3129 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
3130 phosphor::logging::entry("ERR=%s", e.what()));
3131 return ipmi::responseResponseError();
3132 }
3133 }
3134
3135 return ipmi::responseSuccess();
3136}
3137
3138ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
3139{
3140
3141 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
3142 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
3143 {
3144 return ipmi::responseInvalidFieldRequest();
3145 }
3146
3147 std::ifstream jsonStream(dimmOffsetFile);
3148
3149 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
3150 if (json.is_discarded())
3151 {
3152 std::cerr << "File error in " << dimmOffsetFile << "\n";
3153 return ipmi::responseResponseError();
3154 }
3155
3156 std::string typeName;
3157 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
3158 {
3159 typeName = dimmOffset::dimmPower;
3160 }
3161 else
3162 {
3163 typeName = dimmOffset::staticCltt;
3164 }
3165
3166 auto it = json.find(typeName);
3167 if (it == json.end())
3168 {
3169 return ipmi::responseInvalidFieldRequest();
3170 }
3171
3172 if (it->size() <= index)
3173 {
3174 return ipmi::responseInvalidFieldRequest();
3175 }
3176
3177 uint8_t resp = it->at(index).get<uint8_t>();
3178 return ipmi::responseSuccess(resp);
3179}
3180
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003181namespace boot_options
3182{
3183
3184using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server;
3185using IpmiValue = uint8_t;
3186constexpr auto ipmiDefault = 0;
3187
3188std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = {
3189 {0x01, Source::Sources::Network},
3190 {0x02, Source::Sources::Disk},
3191 {0x05, Source::Sources::ExternalMedia},
3192 {0x0f, Source::Sources::RemovableMedia},
3193 {ipmiDefault, Source::Sources::Default}};
3194
3195std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003196 {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003197
3198std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = {
3199 {Source::Sources::Network, 0x01},
3200 {Source::Sources::Disk, 0x02},
3201 {Source::Sources::ExternalMedia, 0x05},
3202 {Source::Sources::RemovableMedia, 0x0f},
3203 {Source::Sources::Default, ipmiDefault}};
3204
3205std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = {
Chen Yugangca12a7b2019-09-03 18:11:44 +08003206 {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}};
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003207
3208static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode";
3209static constexpr auto bootSourceIntf =
3210 "xyz.openbmc_project.Control.Boot.Source";
3211static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable";
3212static constexpr auto persistentObjPath =
3213 "/xyz/openbmc_project/control/host0/boot";
3214static constexpr auto oneTimePath =
3215 "/xyz/openbmc_project/control/host0/boot/one_time";
3216static constexpr auto bootSourceProp = "BootSource";
3217static constexpr auto bootModeProp = "BootMode";
3218static constexpr auto oneTimeBootEnableProp = "Enabled";
3219static constexpr auto httpBootMode =
3220 "xyz.openbmc_project.Control.Boot.Source.Sources.Http";
3221
3222enum class BootOptionParameter : size_t
3223{
3224 setInProgress = 0x0,
3225 bootFlags = 0x5,
3226};
3227static constexpr uint8_t setComplete = 0x0;
3228static constexpr uint8_t setInProgress = 0x1;
3229static uint8_t transferStatus = setComplete;
3230static constexpr uint8_t setParmVersion = 0x01;
3231static constexpr uint8_t setParmBootFlagsPermanent = 0x40;
3232static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80;
3233static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0;
3234static constexpr uint8_t httpBoot = 0xd;
3235static constexpr uint8_t bootSourceMask = 0x3c;
3236
3237} // namespace boot_options
3238
3239ipmi::RspType<uint8_t, // version
3240 uint8_t, // param
3241 uint8_t, // data0, dependent on parameter
3242 std::optional<uint8_t> // data1, dependent on parameter
3243 >
3244 ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block)
3245{
3246 using namespace boot_options;
3247 uint8_t bootOption = 0;
3248
3249 if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3250 {
3251 return ipmi::responseSuccess(setParmVersion, parameter, transferStatus,
3252 std::nullopt);
3253 }
3254
3255 if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags))
3256 {
3257 phosphor::logging::log<phosphor::logging::level::ERR>(
3258 "Unsupported parameter");
3259 return ipmi::responseResponseError();
3260 }
3261
3262 try
3263 {
3264 auto oneTimeEnabled = false;
3265 // read one time Enabled property
3266 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3267 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3268 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3269 enabledIntf, oneTimeBootEnableProp);
3270 oneTimeEnabled = std::get<bool>(variant);
3271
3272 // get BootSource and BootMode properties
3273 // according to oneTimeEnable
3274 auto bootObjPath = oneTimePath;
3275 if (oneTimeEnabled == false)
3276 {
3277 bootObjPath = persistentObjPath;
3278 }
3279
3280 service = getService(*dbus, bootModeIntf, bootObjPath);
3281 variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf,
3282 bootModeProp);
3283
3284 auto bootMode =
3285 Mode::convertModesFromString(std::get<std::string>(variant));
3286
3287 service = getService(*dbus, bootSourceIntf, bootObjPath);
3288 variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3289 bootSourceProp);
3290
3291 if (std::get<std::string>(variant) == httpBootMode)
3292 {
3293 bootOption = httpBoot;
3294 }
3295 else
3296 {
3297 auto bootSource = Source::convertSourcesFromString(
3298 std::get<std::string>(variant));
3299 bootOption = sourceDbusToIpmi.at(bootSource);
3300 if (Source::Sources::Default == bootSource)
3301 {
3302 bootOption = modeDbusToIpmi.at(bootMode);
3303 }
3304 }
3305
3306 uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime
3307 : setParmBootFlagsValidPermanent;
3308 bootOption <<= 2; // shift for responseconstexpr
3309 return ipmi::responseSuccess(setParmVersion, parameter, oneTime,
3310 bootOption);
3311 }
3312 catch (sdbusplus::exception_t& e)
3313 {
3314 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3315 return ipmi::responseResponseError();
3316 }
3317}
3318
3319ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam,
3320 std::optional<uint8_t> bootOption)
3321{
3322 using namespace boot_options;
3323 auto oneTimeEnabled = false;
3324
3325 if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress))
3326 {
3327 if (bootOption)
3328 {
3329 return ipmi::responseReqDataLenInvalid();
3330 }
3331
3332 if (transferStatus == setInProgress)
3333 {
3334 phosphor::logging::log<phosphor::logging::level::ERR>(
3335 "boot option set in progress!");
3336 return ipmi::responseResponseError();
3337 }
3338
3339 transferStatus = bootParam;
3340 return ipmi::responseSuccess();
3341 }
3342
3343 if (bootFlag != (uint8_t)BootOptionParameter::bootFlags)
3344 {
3345 phosphor::logging::log<phosphor::logging::level::ERR>(
3346 "Unsupported parameter");
3347 return ipmi::responseResponseError();
3348 }
3349
3350 if (!bootOption)
3351 {
3352 return ipmi::responseReqDataLenInvalid();
3353 }
3354
3355 if (((bootOption.value() & bootSourceMask) >> 2) !=
3356 httpBoot) // not http boot, exit
3357 {
3358 phosphor::logging::log<phosphor::logging::level::ERR>(
3359 "wrong boot option parameter!");
3360 return ipmi::responseParmOutOfRange();
3361 }
3362
3363 try
3364 {
3365 bool permanent = (bootParam & setParmBootFlagsPermanent) ==
3366 setParmBootFlagsPermanent;
3367
3368 // read one time Enabled property
3369 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
3370 std::string service = getService(*dbus, enabledIntf, oneTimePath);
3371 Value variant = getDbusProperty(*dbus, service, oneTimePath,
3372 enabledIntf, oneTimeBootEnableProp);
3373 oneTimeEnabled = std::get<bool>(variant);
3374
3375 /*
3376 * Check if the current boot setting is onetime or permanent, if the
3377 * request in the command is otherwise, then set the "Enabled"
3378 * property in one_time object path to 'True' to indicate onetime
3379 * and 'False' to indicate permanent.
3380 *
3381 * Once the onetime/permanent setting is applied, then the bootMode
3382 * and bootSource is updated for the corresponding object.
3383 */
3384 if (permanent == oneTimeEnabled)
3385 {
3386 setDbusProperty(*dbus, service, oneTimePath, enabledIntf,
3387 oneTimeBootEnableProp, !permanent);
3388 }
3389
3390 // set BootSource and BootMode properties
3391 // according to oneTimeEnable or persistent
3392 auto bootObjPath = oneTimePath;
3393 if (oneTimeEnabled == false)
3394 {
3395 bootObjPath = persistentObjPath;
3396 }
3397 std::string bootMode =
3398 "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular";
3399 std::string bootSource = httpBootMode;
3400
3401 service = getService(*dbus, bootModeIntf, bootObjPath);
3402 setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp,
3403 bootMode);
3404
3405 service = getService(*dbus, bootSourceIntf, bootObjPath);
3406 setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf,
3407 bootSourceProp, bootSource);
3408 }
3409 catch (sdbusplus::exception_t& e)
3410 {
3411 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
3412 return ipmi::responseResponseError();
3413 }
3414
3415 return ipmi::responseSuccess();
3416}
3417
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003418using BasicVariantType =
3419 std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string,
3420 int64_t, uint64_t, double, int32_t, uint32_t, int16_t,
3421 uint16_t, uint8_t, bool>;
3422using PropertyMapType =
3423 boost::container::flat_map<std::string, BasicVariantType>;
3424static constexpr const std::array<const char*, 1> psuPresenceTypes = {
3425 "xyz.openbmc_project.Configuration.PSUPresence"};
3426int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus,
3427 std::vector<uint64_t>& addrTable)
3428{
3429 boost::system::error_code ec;
3430 GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>(
3431 ctx->yield, ec, "xyz.openbmc_project.ObjectMapper",
3432 "/xyz/openbmc_project/object_mapper",
3433 "xyz.openbmc_project.ObjectMapper", "GetSubTree",
3434 "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes);
3435 if (ec)
3436 {
3437 phosphor::logging::log<phosphor::logging::level::ERR>(
3438 "Failed to set dbus property to cold redundancy");
3439 return -1;
3440 }
3441 for (const auto& object : subtree)
3442 {
3443 std::string pathName = object.first;
3444 for (const auto& serviceIface : object.second)
3445 {
3446 std::string serviceName = serviceIface.first;
3447
3448 ec.clear();
3449 PropertyMapType propMap =
3450 ctx->bus->yield_method_call<PropertyMapType>(
3451 ctx->yield, ec, serviceName, pathName,
3452 "org.freedesktop.DBus.Properties", "GetAll",
3453 "xyz.openbmc_project.Configuration.PSUPresence");
3454 if (ec)
3455 {
3456 phosphor::logging::log<phosphor::logging::level::ERR>(
3457 "Failed to set dbus property to cold redundancy");
3458 return -1;
3459 }
3460 auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]);
3461 auto psuAddress =
3462 std::get_if<std::vector<uint64_t>>(&propMap["Address"]);
3463
3464 if (psuBus == nullptr || psuAddress == nullptr)
3465 {
3466 std::cerr << "error finding necessary "
3467 "entry in configuration\n";
3468 return -1;
3469 }
3470 bus = static_cast<uint8_t>(*psuBus);
3471 addrTable = *psuAddress;
3472 return 0;
3473 }
3474 }
3475 return -1;
3476}
3477
3478static const constexpr uint8_t addrOffset = 8;
3479static const constexpr uint8_t psuRevision = 0xd9;
3480static const constexpr uint8_t defaultPSUBus = 7;
3481// Second Minor, Primary Minor, Major
3482static const constexpr size_t verLen = 3;
3483ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx)
3484{
3485 uint8_t bus = defaultPSUBus;
3486 std::vector<uint64_t> addrTable;
3487 std::vector<uint8_t> result;
3488 if (getPSUAddress(ctx, bus, addrTable))
3489 {
3490 std::cerr << "Failed to get PSU bus and address\n";
3491 return ipmi::responseResponseError();
3492 }
3493
3494 for (const auto& slaveAddr : addrTable)
3495 {
3496 std::vector<uint8_t> writeData = {psuRevision};
3497 std::vector<uint8_t> readBuf(verLen);
3498 uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset;
3499 std::string i2cBus = "/dev/i2c-" + std::to_string(bus);
3500
3501 auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf);
3502 if (retI2C != ipmi::ccSuccess)
3503 {
3504 for (size_t idx = 0; idx < verLen; idx++)
3505 {
3506 result.emplace_back(0x00);
3507 }
3508 }
3509 else
3510 {
3511 for (const uint8_t& data : readBuf)
3512 {
3513 result.emplace_back(data);
3514 }
3515 }
3516 }
3517
3518 return ipmi::responseSuccess(result);
3519}
3520
AppaRao Puli28972062019-11-11 02:04:45 +05303521/** @brief implements the maximum size of
3522 * bridgeable messages used between KCS and
3523 * IPMB interfacesget security mode command.
3524 *
3525 * @returns IPMI completion code with following data
3526 * - KCS Buffer Size (In multiples of four bytes)
3527 * - IPMB Buffer Size (In multiples of four bytes)
3528 **/
3529ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize()
3530{
3531 // for now this is hard coded; really this number is dependent on
3532 // the BMC kcs driver as well as the host kcs driver....
3533 // we can't know the latter.
3534 uint8_t kcsMaxBufferSize = 63 / 4;
3535 uint8_t ipmbMaxBufferSize = 128 / 4;
3536
3537 return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize);
3538}
3539
Jason M. Bills64796042018-10-03 16:51:55 -07003540static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003541{
3542 phosphor::logging::log<phosphor::logging::level::INFO>(
3543 "Registering OEM commands");
Vernon Mauery98bbf692019-09-16 11:14:59 -07003544 ipmiPrintAndRegister(intel::netFnGeneral, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003545 ipmiOEMWildcard,
3546 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003547
3548 ipmiPrintAndRegister(intel::netFnApp, IPMI_CMD_WILDCARD, NULL,
Jason M. Bills64796042018-10-03 16:51:55 -07003549 ipmiOEMWildcard,
3550 PRIVILEGE_USER); // wildcard default handler
Vernon Mauery98bbf692019-09-16 11:14:59 -07003551
3552 ipmiPrintAndRegister(intel::netFnGeneral,
3553 intel::general::cmdGetChassisIdentifier, NULL,
3554 ipmiOEMGetChassisIdentifier,
3555 PRIVILEGE_USER); // get chassis identifier
3556
3557 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID,
3558 NULL, ipmiOEMSetSystemGUID,
3559 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07003560
3561 // <Disable BMC System Reset Action>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003562 registerHandler(prioOemBase, intel::netFnGeneral,
3563 intel::general::cmdDisableBMCSystemReset, Privilege::Admin,
3564 ipmiOEMDisableBMCSystemReset);
3565
Jason M. Billsb02bf092019-08-15 13:01:56 -07003566 // <Get BMC Reset Disables>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003567 registerHandler(prioOemBase, intel::netFnGeneral,
3568 intel::general::cmdGetBMCResetDisables, Privilege::Admin,
3569 ipmiOEMGetBMCResetDisables);
Jason M. Billsb02bf092019-08-15 13:01:56 -07003570
Vernon Mauery98bbf692019-09-16 11:14:59 -07003571 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID,
3572 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003573
Chen Yugang7a04f3a2019-10-08 11:12:35 +08003574 registerHandler(prioOemBase, intel::netFnGeneral,
3575 intel::general::cmdGetOEMDeviceInfo, Privilege::User,
3576 ipmiOEMGetDeviceInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08003577
Vernon Mauery98bbf692019-09-16 11:14:59 -07003578 ipmiPrintAndRegister(intel::netFnGeneral,
3579 intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL,
3580 ipmiOEMGetAICFRU, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303581
Vernon Mauery98bbf692019-09-16 11:14:59 -07003582 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3583 intel::general::cmdSendEmbeddedFWUpdStatus,
3584 Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05303585
Vernon Mauery98bbf692019-09-16 11:14:59 -07003586 ipmiPrintAndRegister(intel::netFnGeneral,
3587 intel::general::cmdSetPowerRestoreDelay, NULL,
3588 ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
3589
3590 ipmiPrintAndRegister(intel::netFnGeneral,
3591 intel::general::cmdGetPowerRestoreDelay, NULL,
3592 ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
3593
3594 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3595 intel::general::cmdSetOEMUser2Activation,
3596 Privilege::Callback, ipmiOEMSetUser2Activation);
3597
3598 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3599 intel::general::cmdSetSpecialUserPassword,
3600 Privilege::Callback, ipmiOEMSetSpecialUserPassword);
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05303601
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003602 // <Get Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003603 registerHandler(prioOemBase, intel::netFnGeneral,
3604 intel::general::cmdGetProcessorErrConfig, Privilege::User,
3605 ipmiOEMGetProcessorErrConfig);
3606
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003607 // <Set Processor Error Config>
Vernon Mauery98bbf692019-09-16 11:14:59 -07003608 registerHandler(prioOemBase, intel::netFnGeneral,
3609 intel::general::cmdSetProcessorErrConfig, Privilege::Admin,
3610 ipmiOEMSetProcessorErrConfig);
Jason M. Bills42bd9c82019-06-28 16:39:34 -07003611
Vernon Mauery98bbf692019-09-16 11:14:59 -07003612 ipmiPrintAndRegister(intel::netFnGeneral,
3613 intel::general::cmdSetShutdownPolicy, NULL,
3614 ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003615
Vernon Mauery98bbf692019-09-16 11:14:59 -07003616 ipmiPrintAndRegister(intel::netFnGeneral,
3617 intel::general::cmdGetShutdownPolicy, NULL,
3618 ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08003619
anil kumar appanaf945eee2019-09-25 23:29:11 +00003620 registerHandler(prioOemBase, intel::netFnGeneral,
3621 intel::general::cmdSetFanConfig, Privilege::User,
3622 ipmiOEMSetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08003623
Vernon Mauery98bbf692019-09-16 11:14:59 -07003624 registerHandler(prioOemBase, intel::netFnGeneral,
3625 intel::general::cmdGetFanConfig, Privilege::User,
3626 ipmiOEMGetFanConfig);
James Feist5f957ca2019-03-14 15:33:55 -07003627
Vernon Mauery98bbf692019-09-16 11:14:59 -07003628 registerHandler(prioOemBase, intel::netFnGeneral,
3629 intel::general::cmdGetFanSpeedOffset, Privilege::User,
3630 ipmiOEMGetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003631
Vernon Mauery98bbf692019-09-16 11:14:59 -07003632 registerHandler(prioOemBase, intel::netFnGeneral,
3633 intel::general::cmdSetFanSpeedOffset, Privilege::User,
3634 ipmiOEMSetFanSpeedOffset);
James Feistacc8a4e2019-04-02 14:23:57 -07003635
Vernon Mauery98bbf692019-09-16 11:14:59 -07003636 registerHandler(prioOemBase, intel::netFnGeneral,
3637 intel::general::cmdSetFscParameter, Privilege::User,
3638 ipmiOEMSetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07003639
Vernon Mauery98bbf692019-09-16 11:14:59 -07003640 registerHandler(prioOemBase, intel::netFnGeneral,
3641 intel::general::cmdGetFscParameter, Privilege::User,
3642 ipmiOEMGetFscParameter);
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05303643
Vernon Mauery98bbf692019-09-16 11:14:59 -07003644 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
3645 intel::general::cmdReadBaseBoardProductId, Privilege::Admin,
3646 ipmiOEMReadBoardProductId);
Chen Yugang39736d52019-07-12 16:24:33 +08003647
Vernon Mauery98bbf692019-09-16 11:14:59 -07003648 registerHandler(prioOemBase, intel::netFnGeneral,
3649 intel::general::cmdGetNmiStatus, Privilege::User,
3650 ipmiOEMGetNmiSource);
Chen Yugang39736d52019-07-12 16:24:33 +08003651
Vernon Mauery98bbf692019-09-16 11:14:59 -07003652 registerHandler(prioOemBase, intel::netFnGeneral,
3653 intel::general::cmdSetNmiStatus, Privilege::Operator,
3654 ipmiOEMSetNmiSource);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003655
Vernon Mauery98bbf692019-09-16 11:14:59 -07003656 registerHandler(prioOemBase, intel::netFnGeneral,
3657 intel::general::cmdGetEfiBootOptions, Privilege::User,
3658 ipmiOemGetEfiBootOptions);
Chen,Yugang4f7e76b2019-08-20 09:28:06 +08003659
Vernon Mauery98bbf692019-09-16 11:14:59 -07003660 registerHandler(prioOemBase, intel::netFnGeneral,
3661 intel::general::cmdSetEfiBootOptions, Privilege::Operator,
3662 ipmiOemSetEfiBootOptions);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303663
Vernon Mauery98bbf692019-09-16 11:14:59 -07003664 registerHandler(prioOemBase, intel::netFnGeneral,
3665 intel::general::cmdGetSecurityMode, Privilege::User,
3666 ipmiGetSecurityMode);
Richard Marian Thomaiyard801e462019-06-20 01:05:40 +05303667
Vernon Mauery98bbf692019-09-16 11:14:59 -07003668 registerHandler(prioOemBase, intel::netFnGeneral,
3669 intel::general::cmdSetSecurityMode, Privilege::Admin,
3670 ipmiSetSecurityMode);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003671
Vernon Mauery98bbf692019-09-16 11:14:59 -07003672 ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdGetLEDStatus,
3673 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Cheng C Yang773703a2019-08-15 09:41:11 +08003674
Vernon Mauery98bbf692019-09-16 11:14:59 -07003675 ipmiPrintAndRegister(ipmi::intel::netFnPlatform,
3676 ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL,
3677 ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
3678
3679 registerHandler(prioOemBase, intel::netFnGeneral,
3680 intel::general::cmdSetFaultIndication, Privilege::Operator,
3681 ipmiOEMSetFaultIndication);
3682
3683 registerHandler(prioOemBase, intel::netFnGeneral,
3684 intel::general::cmdSetColdRedundancyConfig, Privilege::User,
3685 ipmiOEMSetCRConfig);
3686
3687 registerHandler(prioOemBase, intel::netFnGeneral,
3688 intel::general::cmdGetColdRedundancyConfig, Privilege::User,
3689 ipmiOEMGetCRConfig);
3690
3691 registerHandler(prioOemBase, intel::netFnGeneral,
3692 intel::general::cmdRestoreConfiguration, Privilege::Admin,
Vernon Mauery4ac799d2019-05-20 15:50:37 -07003693 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07003694
Vernon Mauery98bbf692019-09-16 11:14:59 -07003695 registerHandler(prioOemBase, intel::netFnGeneral,
3696 intel::general::cmdSetDimmOffset, Privilege::Operator,
3697 ipmiOEMSetDimmOffset);
James Feist63efafa2019-07-24 12:39:21 -07003698
Vernon Mauery98bbf692019-09-16 11:14:59 -07003699 registerHandler(prioOemBase, intel::netFnGeneral,
3700 intel::general::cmdGetDimmOffset, Privilege::Operator,
3701 ipmiOEMGetDimmOffset);
Chen Yugangca12a7b2019-09-03 18:11:44 +08003702
Cheng C Yang4e6ee152019-09-25 10:27:44 +08003703 registerHandler(prioOemBase, intel::netFnGeneral,
3704 intel::general::cmdGetPSUVersion, Privilege::User,
3705 ipmiOEMGetPSUVersion);
AppaRao Puli28972062019-11-11 02:04:45 +05303706
3707 registerHandler(prioOemBase, intel::netFnGeneral,
3708 intel::general::cmdGetBufferSize, Privilege::User,
3709 ipmiOEMGetBufferSize);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08003710}
3711
3712} // namespace ipmi