blob: aa8330e41e769be13f1f850069f7d39e6f9d32c7 [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
22#include <array>
James Feist91244a62019-02-19 15:04:54 -080023#include <boost/container/flat_map.hpp>
Yong Li23737fe2019-02-19 08:49:55 +080024#include <boost/process/child.hpp>
25#include <boost/process/io.hpp>
Chen Yugang39736d52019-07-12 16:24:33 +080026#include <com/intel/Control/NMISource/server.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>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080030#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080031#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070032#include <ipmid/utils.hpp>
James Feist63efafa2019-07-24 12:39:21 -070033#include <nlohmann/json.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035#include <phosphor-logging/log.hpp>
36#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053037#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080038#include <string>
James Feist91244a62019-02-19 15:04:54 -080039#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080040#include <vector>
Cheng C Yang773703a2019-08-15 09:41:11 +080041#include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080042
43namespace ipmi
44{
Jason M. Bills64796042018-10-03 16:51:55 -070045static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070046
47namespace netfn::intel
48{
49constexpr NetFn oemGeneral = netFnOemOne;
50constexpr Cmd cmdRestoreConfiguration = 0x02;
51} // namespace netfn::intel
52
Jason M. Bills64796042018-10-03 16:51:55 -070053static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080054
Suryakanth Sekard509eb92018-11-15 17:44:11 +053055static constexpr auto ethernetIntf =
56 "xyz.openbmc_project.Network.EthernetInterface";
57static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
58static constexpr auto networkService = "xyz.openbmc_project.Network";
59static constexpr auto networkRoot = "/xyz/openbmc_project/network";
60
Chen Yugang39736d52019-07-12 16:24:33 +080061static constexpr const char* oemNmiSourceIntf = "com.intel.Control.NMISource";
62static constexpr const char* oemNmiSourceObjPath =
63 "/com/intel/control/NMISource";
64static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
65static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
66
James Feist63efafa2019-07-24 12:39:21 -070067static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json";
68
Chen Yugang39736d52019-07-12 16:24:33 +080069enum class NmiSource : uint8_t
70{
71 none = 0,
72 fpBtn = 1,
73 wdPreTimeout = 2,
74 pefMatch = 3,
75 chassisCmd = 4,
76 memoryError = 5,
77 pciSerrPerr = 6,
78 southbridgeNmi = 7,
79 chipsetNmi = 8,
80};
81
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080082// return code: 0 successful
83int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
84{
85 std::string objpath = "/xyz/openbmc_project/FruDevice";
86 std::string intf = "xyz.openbmc_project.FruDeviceManager";
87 std::string service = getService(bus, intf, objpath);
88 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
89 if (valueTree.empty())
90 {
91 phosphor::logging::log<phosphor::logging::level::ERR>(
92 "No object implements interface",
93 phosphor::logging::entry("INTF=%s", intf.c_str()));
94 return -1;
95 }
96
Jason M. Bills64796042018-10-03 16:51:55 -070097 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080098 {
99 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
100 if (interface == item.second.end())
101 {
102 continue;
103 }
104
105 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
106 if (property == interface->second.end())
107 {
108 continue;
109 }
110
111 try
112 {
113 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700114 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700115 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800116 {
117 phosphor::logging::log<phosphor::logging::level::ERR>(
118 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800119 return -1;
120 }
Jason M. Bills64796042018-10-03 16:51:55 -0700121 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800122 return 0;
123 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700124 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800125 {
Jason M. Bills64796042018-10-03 16:51:55 -0700126 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800127 return -1;
128 }
129 }
130 return -1;
131}
Jason M. Bills64796042018-10-03 16:51:55 -0700132
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800133ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
134 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700135 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800136{
Jason M. Bills64796042018-10-03 16:51:55 -0700137 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800138 // Status code.
139 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700140 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800141 return rc;
142}
143
144// Returns the Chassis Identifier (serial #)
145ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
146 ipmi_request_t request,
147 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700148 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800149 ipmi_context_t context)
150{
151 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700152 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800153 {
Jason M. Bills64796042018-10-03 16:51:55 -0700154 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800155 return IPMI_CC_REQ_DATA_LEN_INVALID;
156 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700157 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
158 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800159 {
Jason M. Bills64796042018-10-03 16:51:55 -0700160 *dataLen = serial.size(); // length will never exceed response length
161 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700163 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800164 return IPMI_CC_OK;
165 }
Jason M. Bills64796042018-10-03 16:51:55 -0700166 *dataLen = 0;
167 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800168}
169
170ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
171 ipmi_request_t request,
172 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700173 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800174{
175 static constexpr size_t safeBufferLength = 50;
176 char buf[safeBufferLength] = {0};
177 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
178
Jason M. Bills64796042018-10-03 16:51:55 -0700179 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800180 {
Jason M. Bills64796042018-10-03 16:51:55 -0700181 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800182 return IPMI_CC_REQ_DATA_LEN_INVALID;
183 }
184
Jason M. Bills64796042018-10-03 16:51:55 -0700185 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800186
187 snprintf(
188 buf, safeBufferLength,
189 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
190 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
191 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
192 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
193 Data->node3, Data->node2, Data->node1);
194 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
195 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800196
197 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
198 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700199 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
200 std::string service = getService(*dbus, intf, objpath);
201 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800202 return IPMI_CC_OK;
203}
204
Jason M. Billsb02bf092019-08-15 13:01:56 -0700205ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI,
206 uint7_t reserved1)
207{
208 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
209
210 try
211 {
212 auto service =
213 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
214 ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath,
215 bmcResetDisablesIntf, "ResetOnSMI",
216 !disableResetOnSMI);
217 }
218 catch (std::exception& e)
219 {
220 phosphor::logging::log<phosphor::logging::level::ERR>(
221 "Failed to set BMC reset disables",
222 phosphor::logging::entry("EXCEPTION=%s", e.what()));
223 return ipmi::responseUnspecifiedError();
224 }
225
226 return ipmi::responseSuccess();
227}
228
229ipmi::RspType<bool, // disableResetOnSMI
230 uint7_t // reserved
231 >
232 ipmiOEMGetBMCResetDisables()
233{
234 bool disableResetOnSMI = true;
235
236 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
237 try
238 {
239 auto service =
240 ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath);
241 Value variant =
242 ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath,
243 bmcResetDisablesIntf, "ResetOnSMI");
244 disableResetOnSMI = !std::get<bool>(variant);
245 }
246 catch (std::exception& e)
247 {
248 phosphor::logging::log<phosphor::logging::level::ERR>(
249 "Failed to get BMC reset disables",
250 phosphor::logging::entry("EXCEPTION=%s", e.what()));
251 return ipmi::responseUnspecifiedError();
252 }
253
254 return ipmi::responseSuccess(disableResetOnSMI, 0);
255}
256
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800257ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
258 ipmi_request_t request, ipmi_response_t response,
259 ipmi_data_len_t dataLen, ipmi_context_t context)
260{
261 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
262
Jason M. Bills64796042018-10-03 16:51:55 -0700263 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800264 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800265 *dataLen = 0;
266 return IPMI_CC_REQ_DATA_LEN_INVALID;
267 }
Jason M. Bills64796042018-10-03 16:51:55 -0700268 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800269
Vernon Mauery15419dd2019-05-24 09:40:30 -0700270 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
271 std::string service = getService(*dbus, biosIntf, biosObjPath);
272 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800273 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
274 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700275 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800276 *dataLen = 1;
277 return IPMI_CC_OK;
278}
279
280ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
281 ipmi_request_t request,
282 ipmi_response_t response,
283 ipmi_data_len_t dataLen, ipmi_context_t context)
284{
285 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
286 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
287
288 if (*dataLen == 0)
289 {
Jason M. Bills64796042018-10-03 16:51:55 -0700290 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800291 return IPMI_CC_REQ_DATA_LEN_INVALID;
292 }
293
294 size_t reqDataLen = *dataLen;
295 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700296 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800297 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800298 return IPMI_CC_INVALID_FIELD_REQUEST;
299 }
300
301 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700302 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800303 {
304 case OEMDevEntityType::biosId:
305 {
306 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
307 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800308 return IPMI_CC_REQ_DATA_LEN_INVALID;
309 }
310
Vernon Mauery15419dd2019-05-24 09:40:30 -0700311 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
312 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800313 try
314 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700315 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800316 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700317 std::string& idString = std::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800318 if (req->offset >= idString.size())
319 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800320 return IPMI_CC_PARM_OUT_OF_RANGE;
321 }
Jason M. Bills64796042018-10-03 16:51:55 -0700322 size_t length = 0;
323 if (req->countToRead > (idString.size() - req->offset))
324 {
325 length = idString.size() - req->offset;
326 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800327 else
328 {
Jason M. Bills64796042018-10-03 16:51:55 -0700329 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800330 }
Jason M. Bills64796042018-10-03 16:51:55 -0700331 std::copy(idString.begin() + req->offset, idString.end(),
332 res->data);
333 res->resDatalen = length;
334 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800335 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700336 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800337 {
Jason M. Bills64796042018-10-03 16:51:55 -0700338 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800339 return IPMI_CC_UNSPECIFIED_ERROR;
340 }
341 }
342 break;
343
344 case OEMDevEntityType::devVer:
345 case OEMDevEntityType::sdrVer:
346 // TODO:
347 return IPMI_CC_ILLEGAL_COMMAND;
348 default:
349 return IPMI_CC_INVALID_FIELD_REQUEST;
350 }
351 return IPMI_CC_OK;
352}
353
354ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
355 ipmi_request_t request, ipmi_response_t response,
356 ipmi_data_len_t dataLen, ipmi_context_t context)
357{
358 if (*dataLen != 0)
359 {
Jason M. Bills64796042018-10-03 16:51:55 -0700360 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800361 return IPMI_CC_REQ_DATA_LEN_INVALID;
362 }
363
364 *dataLen = 1;
365 uint8_t* res = reinterpret_cast<uint8_t*>(response);
366 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
367 // AIC is available so that BIOS will not timeout repeatly which leads to
368 // slow booting.
369 *res = 0; // Byte1=Count of SlotPosition/FruID records.
370 return IPMI_CC_OK;
371}
372
Jason M. Bills64796042018-10-03 16:51:55 -0700373ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
374 ipmi_request_t request,
375 ipmi_response_t response,
376 ipmi_data_len_t dataLen,
377 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800378{
Jason M. Bills64796042018-10-03 16:51:55 -0700379 GetPowerRestoreDelayRes* resp =
380 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
381
382 if (*dataLen != 0)
383 {
384 *dataLen = 0;
385 return IPMI_CC_REQ_DATA_LEN_INVALID;
386 }
387
Vernon Mauery15419dd2019-05-24 09:40:30 -0700388 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700389 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700390 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700391 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700392 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700393 powerRestoreDelayIntf, powerRestoreDelayProp);
394
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700395 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700396 resp->byteLSB = delay;
397 resp->byteMSB = delay >> 8;
398
399 *dataLen = sizeof(GetPowerRestoreDelayRes);
400
401 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800402}
403
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800404static uint8_t bcdToDec(uint8_t val)
405{
406 return ((val / 16 * 10) + (val % 16));
407}
408
409// Allows an update utility or system BIOS to send the status of an embedded
410// firmware update attempt to the BMC. After received, BMC will create a logging
411// record.
412ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
413 uint8_t majorRevision,
414 uint8_t minorRevision,
415 uint32_t auxInfo)
416{
417 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700418 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800419 target = (target & selEvtTargetMask) >> selEvtTargetShift;
420
421 /* make sure the status is 0, 1, or 2 as per the spec */
422 if (status > 2)
423 {
424 return ipmi::response(ipmi::ccInvalidFieldRequest);
425 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700426 /* make sure the target is 0, 1, 2, or 4 as per the spec */
427 if (target > 4 || target == 3)
428 {
429 return ipmi::response(ipmi::ccInvalidFieldRequest);
430 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800431 /*orignal OEM command is to record OEM SEL.
432 But openbmc does not support OEM SEL, so we redirect it to redfish event
433 logging. */
434 std::string buildInfo;
435 std::string action;
436 switch (FWUpdateTarget(target))
437 {
438 case FWUpdateTarget::targetBMC:
439 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700440 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800441 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
442 " BuildID: " + std::to_string(auxInfo);
443 buildInfo += std::to_string(auxInfo);
444 break;
445 case FWUpdateTarget::targetBIOS:
446 firmware = "BIOS";
447 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700448 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800449 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
450 " minor: " +
451 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
452 " ReleaseNumber: " + // ASCII encoded
453 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
454 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
455 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
456 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
457 break;
458 case FWUpdateTarget::targetME:
459 firmware = "ME";
460 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700461 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800462 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
463 " minor2: " +
464 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
465 " build1: " +
466 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
467 " build2: " +
468 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
469 break;
470 case FWUpdateTarget::targetOEMEWS:
471 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700472 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800473 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
474 " BuildID: " + std::to_string(auxInfo);
475 break;
476 }
477
Jason M. Billsdc249272019-04-03 09:58:40 -0700478 static const std::string openBMCMessageRegistryVersion("0.1");
479 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
480
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800481 switch (status)
482 {
483 case 0x0:
484 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700485 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800486 break;
487 case 0x1:
488 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700489 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800490 break;
491 case 0x2:
492 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700493 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800494 break;
495 default:
496 action = "unknown";
497 break;
498 }
499
Jason M. Billsdc249272019-04-03 09:58:40 -0700500 std::string firmwareInstanceStr =
501 firmware + " instance: " + std::to_string(instance);
502 std::string message("[firmware update] " + firmwareInstanceStr +
503 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800504
505 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700506 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
507 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
508 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800509 return ipmi::responseSuccess();
510}
511
Jason M. Bills64796042018-10-03 16:51:55 -0700512ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
513 ipmi_request_t request,
514 ipmi_response_t response,
515 ipmi_data_len_t dataLen,
516 ipmi_context_t context)
517{
518 SetPowerRestoreDelayReq* data =
519 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
520 uint16_t delay = 0;
521
522 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
523 {
524 *dataLen = 0;
525 return IPMI_CC_REQ_DATA_LEN_INVALID;
526 }
527 delay = data->byteMSB;
528 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700529 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700530 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700531 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
532 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700533 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
534 *dataLen = 0;
535
536 return IPMI_CC_OK;
537}
538
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700539static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700540{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700541 static constexpr const char* cpuPresencePathPrefix =
542 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
543 static constexpr const char* cpuPresenceIntf =
544 "xyz.openbmc_project.Inventory.Item";
545 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
546 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
547 try
Jason M. Bills64796042018-10-03 16:51:55 -0700548 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700549 auto service =
550 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
551
552 ipmi::Value result = ipmi::getDbusProperty(
553 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
554 return std::get<bool>(result);
555 }
556 catch (const std::exception& e)
557 {
558 phosphor::logging::log<phosphor::logging::level::INFO>(
559 "Cannot find processor presence",
560 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
561 return false;
562 }
563}
564
565ipmi::RspType<bool, // CATERR Reset Enabled
566 bool, // ERR2 Reset Enabled
567 uint6_t, // reserved
568 uint8_t, // reserved, returns 0x3F
569 uint6_t, // CPU1 CATERR Count
570 uint2_t, // CPU1 Status
571 uint6_t, // CPU2 CATERR Count
572 uint2_t, // CPU2 Status
573 uint6_t, // CPU3 CATERR Count
574 uint2_t, // CPU3 Status
575 uint6_t, // CPU4 CATERR Count
576 uint2_t, // CPU4 Status
577 uint8_t // Crashdump Count
578 >
579 ipmiOEMGetProcessorErrConfig()
580{
581 bool resetOnCATERR = false;
582 bool resetOnERR2 = false;
583 uint6_t cpu1CATERRCount = 0;
584 uint6_t cpu2CATERRCount = 0;
585 uint6_t cpu3CATERRCount = 0;
586 uint6_t cpu4CATERRCount = 0;
587 uint8_t crashdumpCount = 0;
588 uint2_t cpu1Status =
589 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
590 uint2_t cpu2Status =
591 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
592 uint2_t cpu3Status =
593 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
594 uint2_t cpu4Status =
595 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
596
597 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
598 try
599 {
600 auto service = ipmi::getService(*busp, processorErrConfigIntf,
601 processorErrConfigObjPath);
602
603 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
604 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
605 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
606 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
607 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
608 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
609 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
610 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
611 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
612 }
613 catch (const std::exception& e)
614 {
615 phosphor::logging::log<phosphor::logging::level::ERR>(
616 "Failed to fetch processor error config",
617 phosphor::logging::entry("ERROR=%s", e.what()));
618 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700619 }
620
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700621 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
622 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
623 cpu2Status, cpu3CATERRCount, cpu3Status,
624 cpu4CATERRCount, cpu4Status, crashdumpCount);
625}
Jason M. Bills64796042018-10-03 16:51:55 -0700626
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700627ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
628 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
629 std::optional<bool> clearCPUErrorCount,
630 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
631{
632 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700633
634 try
635 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700636 auto service = ipmi::getService(*busp, processorErrConfigIntf,
637 processorErrConfigObjPath);
638 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
639 processorErrConfigIntf, "ResetOnCATERR",
640 resetOnCATERR);
641 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
642 processorErrConfigIntf, "ResetOnERR2",
643 resetOnERR2);
644 if (clearCPUErrorCount.value_or(false))
645 {
646 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700647 processorErrConfigIntf, "ErrorCountCPU1",
648 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700649 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700650 processorErrConfigIntf, "ErrorCountCPU2",
651 static_cast<uint8_t>(0));
652 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
653 processorErrConfigIntf, "ErrorCountCPU3",
654 static_cast<uint8_t>(0));
655 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
656 processorErrConfigIntf, "ErrorCountCPU4",
657 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700658 }
659 if (clearCrashdumpCount.value_or(false))
660 {
661 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
Jason M. Billsd3e19932019-08-15 12:39:03 -0700662 processorErrConfigIntf, "CrashdumpCount",
663 static_cast<uint8_t>(0));
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700664 }
Jason M. Bills64796042018-10-03 16:51:55 -0700665 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700666 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700667 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800668 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700669 "Failed to set processor error config",
670 phosphor::logging::entry("EXCEPTION=%s", e.what()));
671 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700672 }
673
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700674 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700675}
676
Yong Li703922d2018-11-06 13:25:31 +0800677ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
678 ipmi_request_t request,
679 ipmi_response_t response,
680 ipmi_data_len_t dataLen,
681 ipmi_context_t context)
682{
683 GetOEMShutdownPolicyRes* resp =
684 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
685
686 if (*dataLen != 0)
687 {
688 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800689 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800690 *dataLen = 0;
691 return IPMI_CC_REQ_DATA_LEN_INVALID;
692 }
693
694 *dataLen = 0;
695
696 try
697 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700698 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800699 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700700 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
701 Value variant = getDbusProperty(
702 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
703 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800704
705 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
706 convertPolicyFromString(std::get<std::string>(variant)) ==
707 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
708 NoShutdownOnOCOT)
709 {
710 resp->policy = 0;
711 }
712 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
713 convertPolicyFromString(std::get<std::string>(variant)) ==
714 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
715 Policy::ShutdownOnOCOT)
716 {
717 resp->policy = 1;
718 }
719 else
720 {
721 phosphor::logging::log<phosphor::logging::level::ERR>(
722 "oem_set_shutdown_policy: invalid property!",
723 phosphor::logging::entry(
724 "PROP=%s", std::get<std::string>(variant).c_str()));
725 return IPMI_CC_UNSPECIFIED_ERROR;
726 }
Yong Li703922d2018-11-06 13:25:31 +0800727 // TODO needs to check if it is multi-node products,
728 // policy is only supported on node 3/4
729 resp->policySupport = shutdownPolicySupported;
730 }
731 catch (sdbusplus::exception_t& e)
732 {
733 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
734 return IPMI_CC_UNSPECIFIED_ERROR;
735 }
736
737 *dataLen = sizeof(GetOEMShutdownPolicyRes);
738 return IPMI_CC_OK;
739}
740
741ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
742 ipmi_request_t request,
743 ipmi_response_t response,
744 ipmi_data_len_t dataLen,
745 ipmi_context_t context)
746{
747 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800748 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
749 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
750 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800751
752 // TODO needs to check if it is multi-node products,
753 // policy is only supported on node 3/4
754 if (*dataLen != 1)
755 {
756 phosphor::logging::log<phosphor::logging::level::ERR>(
757 "oem_set_shutdown_policy: invalid input len!");
758 *dataLen = 0;
759 return IPMI_CC_REQ_DATA_LEN_INVALID;
760 }
761
762 *dataLen = 0;
763 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
764 {
765 phosphor::logging::log<phosphor::logging::level::ERR>(
766 "oem_set_shutdown_policy: invalid input!");
767 return IPMI_CC_INVALID_FIELD_REQUEST;
768 }
769
Yong Li0669d192019-05-06 14:01:46 +0800770 if (*req == noShutdownOnOCOT)
771 {
772 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
773 Policy::NoShutdownOnOCOT;
774 }
775 else
776 {
777 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
778 Policy::ShutdownOnOCOT;
779 }
780
Yong Li703922d2018-11-06 13:25:31 +0800781 try
782 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700783 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800784 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700785 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800786 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700787 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800788 oemShutdownPolicyObjPathProp,
789 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800790 }
791 catch (sdbusplus::exception_t& e)
792 {
793 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
794 return IPMI_CC_UNSPECIFIED_ERROR;
795 }
796
797 return IPMI_CC_OK;
798}
799
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530800/** @brief implementation for check the DHCP or not in IPv4
801 * @param[in] Channel - Channel number
802 * @returns true or false.
803 */
804static bool isDHCPEnabled(uint8_t Channel)
805{
806 try
807 {
808 auto ethdevice = getChannelName(Channel);
809 if (ethdevice.empty())
810 {
811 return false;
812 }
813 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700814 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530815 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700816 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
817 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530818 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700819 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530820 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
821 {
822 return true;
823 }
824 else
825 {
826 return false;
827 }
828 }
829 catch (sdbusplus::exception_t& e)
830 {
831 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
832 return true;
833 }
834}
835
836/** @brief implementes for check the DHCP or not in IPv6
837 * @param[in] Channel - Channel number
838 * @returns true or false.
839 */
840static bool isDHCPIPv6Enabled(uint8_t Channel)
841{
842
843 try
844 {
845 auto ethdevice = getChannelName(Channel);
846 if (ethdevice.empty())
847 {
848 return false;
849 }
850 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700851 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530852 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700853 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
854 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530855 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700856 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530857 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
858 {
859 return true;
860 }
861 else
862 {
863 return false;
864 }
865 }
866 catch (sdbusplus::exception_t& e)
867 {
868 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
869 return true;
870 }
871}
872
873/** @brief implementes the creating of default new user
874 * @param[in] userName - new username in 16 bytes.
875 * @param[in] userPassword - new password in 20 bytes
876 * @returns ipmi completion code.
877 */
878ipmi::RspType<> ipmiOEMSetUser2Activation(
879 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
880 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
881{
882 bool userState = false;
883 // Check for System Interface not exist and LAN should be static
884 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
885 {
886 ChannelInfo chInfo;
887 try
888 {
889 getChannelInfo(channel, chInfo);
890 }
891 catch (sdbusplus::exception_t& e)
892 {
893 phosphor::logging::log<phosphor::logging::level::ERR>(
894 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
895 phosphor::logging::entry("MSG: %s", e.description()));
896 return ipmi::response(ipmi::ccUnspecifiedError);
897 }
898 if (chInfo.mediumType ==
899 static_cast<uint8_t>(EChannelMediumType::systemInterface))
900 {
901 phosphor::logging::log<phosphor::logging::level::ERR>(
902 "ipmiOEMSetUser2Activation: system interface exist .");
903 return ipmi::response(ipmi::ccCommandNotAvailable);
904 }
905 else
906 {
907
908 if (chInfo.mediumType ==
909 static_cast<uint8_t>(EChannelMediumType::lan8032))
910 {
911 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
912 {
913 phosphor::logging::log<phosphor::logging::level::ERR>(
914 "ipmiOEMSetUser2Activation: DHCP enabled .");
915 return ipmi::response(ipmi::ccCommandNotAvailable);
916 }
917 }
918 }
919 }
920 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
921 if (ipmi::ccSuccess ==
922 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
923 {
924 if (enabledUsers > 1)
925 {
926 phosphor::logging::log<phosphor::logging::level::ERR>(
927 "ipmiOEMSetUser2Activation: more than one user is enabled.");
928 return ipmi::response(ipmi::ccCommandNotAvailable);
929 }
930 // Check the user 2 is enabled or not
931 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
932 if (userState == true)
933 {
934 phosphor::logging::log<phosphor::logging::level::ERR>(
935 "ipmiOEMSetUser2Activation: user 2 already enabled .");
936 return ipmi::response(ipmi::ccCommandNotAvailable);
937 }
938 }
939 else
940 {
941 return ipmi::response(ipmi::ccUnspecifiedError);
942 }
943
944#if BYTE_ORDER == LITTLE_ENDIAN
945 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
946#endif
947#if BYTE_ORDER == BIG_ENDIAN
948 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
949#endif
950
951 if (ipmi::ccSuccess ==
952 ipmiUserSetUserName(ipmiDefaultUserId,
953 reinterpret_cast<const char*>(userName.data())))
954 {
955 if (ipmi::ccSuccess ==
956 ipmiUserSetUserPassword(
957 ipmiDefaultUserId,
958 reinterpret_cast<const char*>(userPassword.data())))
959 {
960 if (ipmi::ccSuccess ==
961 ipmiUserSetPrivilegeAccess(
962 ipmiDefaultUserId,
963 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
964 privAccess, true))
965 {
966 phosphor::logging::log<phosphor::logging::level::INFO>(
967 "ipmiOEMSetUser2Activation: user created successfully ");
968 return ipmi::responseSuccess();
969 }
970 }
971 // we need to delete the default user id which added in this command as
972 // password / priv setting is failed.
973 ipmiUserSetUserName(ipmiDefaultUserId, "");
974 phosphor::logging::log<phosphor::logging::level::ERR>(
975 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
976 }
977 else
978 {
979 phosphor::logging::log<phosphor::logging::level::ERR>(
980 "ipmiOEMSetUser2Activation: Setting username failed.");
981 }
982
983 return ipmi::response(ipmi::ccCommandNotAvailable);
984}
985
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +0530986/** @brief implementes setting password for special user
987 * @param[in] specialUserIndex
988 * @param[in] userPassword - new password in 20 bytes
989 * @returns ipmi completion code.
990 */
991ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
992 uint8_t specialUserIndex,
993 std::vector<uint8_t> userPassword)
994{
995 ChannelInfo chInfo;
996 try
997 {
998 getChannelInfo(ctx->channel, chInfo);
999 }
1000 catch (sdbusplus::exception_t& e)
1001 {
1002 phosphor::logging::log<phosphor::logging::level::ERR>(
1003 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
1004 phosphor::logging::entry("MSG: %s", e.description()));
1005 return ipmi::responseUnspecifiedError();
1006 }
1007 if (chInfo.mediumType !=
1008 static_cast<uint8_t>(EChannelMediumType::systemInterface))
1009 {
1010 phosphor::logging::log<phosphor::logging::level::ERR>(
1011 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
1012 "interface");
1013 return ipmi::responseCommandNotAvailable();
1014 }
1015 if (specialUserIndex != 0)
1016 {
1017 phosphor::logging::log<phosphor::logging::level::ERR>(
1018 "ipmiOEMSetSpecialUserPassword: Invalid user account");
1019 return ipmi::responseParmOutOfRange();
1020 }
1021 constexpr uint8_t minPasswordSizeRequired = 6;
1022 if (userPassword.size() < minPasswordSizeRequired ||
1023 userPassword.size() > ipmi::maxIpmi20PasswordSize)
1024 {
1025 return ipmi::responseReqDataLenInvalid();
1026 }
1027 std::string passwd;
1028 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
1029 userPassword.size());
1030 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
1031}
1032
Kuiying Wang45f04982018-12-26 09:23:08 +08001033namespace ledAction
1034{
1035using namespace sdbusplus::xyz::openbmc_project::Led::server;
1036std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
1037 {Physical::Action::Off, 0x00},
1038 {Physical::Action::On, 0x10},
1039 {Physical::Action::Blink, 0x01}};
1040
1041std::map<uint8_t, std::string> offsetObjPath = {
1042 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
1043
1044} // namespace ledAction
1045
1046int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
1047 const std::string& objPath, uint8_t& state)
1048{
1049 try
1050 {
1051 std::string service = getService(bus, intf, objPath);
1052 Value stateValue =
1053 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -07001054 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +08001055 state = ledAction::actionDbusToIpmi.at(
1056 sdbusplus::xyz::openbmc_project::Led::server::Physical::
1057 convertActionFromString(strState));
1058 }
1059 catch (sdbusplus::exception::SdBusError& e)
1060 {
1061 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1062 return -1;
1063 }
1064 return 0;
1065}
1066
1067ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1068 ipmi_request_t request, ipmi_response_t response,
1069 ipmi_data_len_t dataLen, ipmi_context_t context)
1070{
1071 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1072 // LED Status
1073 //[1:0] = Reserved
1074 //[3:2] = Status(Amber)
1075 //[5:4] = Status(Green)
1076 //[7:6] = System Identify
1077 // Status definitions:
1078 // 00b = Off
1079 // 01b = Blink
1080 // 10b = On
1081 // 11b = invalid
1082 if (*dataLen != 0)
1083 {
1084 phosphor::logging::log<phosphor::logging::level::ERR>(
1085 "oem_get_led_status: invalid input len!");
1086 *dataLen = 0;
1087 return IPMI_CC_REQ_DATA_LEN_INVALID;
1088 }
1089
1090 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1091 *resp = 0;
1092 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001093 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001094 for (auto it = ledAction::offsetObjPath.begin();
1095 it != ledAction::offsetObjPath.end(); ++it)
1096 {
1097 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001098 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001099 {
1100 phosphor::logging::log<phosphor::logging::level::ERR>(
1101 "oem_get_led_status: fail to get ID LED status!");
1102 return IPMI_CC_UNSPECIFIED_ERROR;
1103 }
1104 *resp |= state << it->first;
1105 }
1106
1107 *dataLen = sizeof(*resp);
1108 return IPMI_CC_OK;
1109}
1110
Yong Li23737fe2019-02-19 08:49:55 +08001111ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1112 ipmi_request_t request,
1113 ipmi_response_t response,
1114 ipmi_data_len_t dataLen,
1115 ipmi_context_t context)
1116{
1117 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1118 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1119
1120 if (*dataLen == 0)
1121 {
1122 phosphor::logging::log<phosphor::logging::level::ERR>(
1123 "CfgHostSerial: invalid input len!",
1124 phosphor::logging::entry("LEN=%d", *dataLen));
1125 return IPMI_CC_REQ_DATA_LEN_INVALID;
1126 }
1127
1128 switch (req->command)
1129 {
1130 case getHostSerialCfgCmd:
1131 {
1132 if (*dataLen != 1)
1133 {
1134 phosphor::logging::log<phosphor::logging::level::ERR>(
1135 "CfgHostSerial: invalid input len!");
1136 *dataLen = 0;
1137 return IPMI_CC_REQ_DATA_LEN_INVALID;
1138 }
1139
1140 *dataLen = 0;
1141
1142 boost::process::ipstream is;
1143 std::vector<std::string> data;
1144 std::string line;
1145 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1146 boost::process::std_out > is);
1147
1148 while (c1.running() && std::getline(is, line) && !line.empty())
1149 {
1150 data.push_back(line);
1151 }
1152
1153 c1.wait();
1154 if (c1.exit_code())
1155 {
1156 phosphor::logging::log<phosphor::logging::level::ERR>(
1157 "CfgHostSerial:: error on execute",
1158 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1159 // Using the default value
1160 *resp = 0;
1161 }
1162 else
1163 {
1164 if (data.size() != 1)
1165 {
1166 phosphor::logging::log<phosphor::logging::level::ERR>(
1167 "CfgHostSerial:: error on read env");
1168 return IPMI_CC_UNSPECIFIED_ERROR;
1169 }
1170 try
1171 {
1172 unsigned long tmp = std::stoul(data[0]);
1173 if (tmp > std::numeric_limits<uint8_t>::max())
1174 {
1175 throw std::out_of_range("Out of range");
1176 }
1177 *resp = static_cast<uint8_t>(tmp);
1178 }
1179 catch (const std::invalid_argument& e)
1180 {
1181 phosphor::logging::log<phosphor::logging::level::ERR>(
1182 "invalid config ",
1183 phosphor::logging::entry("ERR=%s", e.what()));
1184 return IPMI_CC_UNSPECIFIED_ERROR;
1185 }
1186 catch (const std::out_of_range& e)
1187 {
1188 phosphor::logging::log<phosphor::logging::level::ERR>(
1189 "out_of_range config ",
1190 phosphor::logging::entry("ERR=%s", e.what()));
1191 return IPMI_CC_UNSPECIFIED_ERROR;
1192 }
1193 }
1194
1195 *dataLen = 1;
1196 break;
1197 }
1198 case setHostSerialCfgCmd:
1199 {
1200 if (*dataLen != sizeof(CfgHostSerialReq))
1201 {
1202 phosphor::logging::log<phosphor::logging::level::ERR>(
1203 "CfgHostSerial: invalid input len!");
1204 *dataLen = 0;
1205 return IPMI_CC_REQ_DATA_LEN_INVALID;
1206 }
1207
1208 *dataLen = 0;
1209
1210 if (req->parameter > HostSerialCfgParamMax)
1211 {
1212 phosphor::logging::log<phosphor::logging::level::ERR>(
1213 "CfgHostSerial: invalid input!");
1214 return IPMI_CC_INVALID_FIELD_REQUEST;
1215 }
1216
1217 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1218 std::to_string(req->parameter));
1219
1220 c1.wait();
1221 if (c1.exit_code())
1222 {
1223 phosphor::logging::log<phosphor::logging::level::ERR>(
1224 "CfgHostSerial:: error on execute",
1225 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1226 return IPMI_CC_UNSPECIFIED_ERROR;
1227 }
1228 break;
1229 }
1230 default:
1231 phosphor::logging::log<phosphor::logging::level::ERR>(
1232 "CfgHostSerial: invalid input!");
1233 *dataLen = 0;
1234 return IPMI_CC_INVALID_FIELD_REQUEST;
1235 }
1236
1237 return IPMI_CC_OK;
1238}
1239
James Feist91244a62019-02-19 15:04:54 -08001240constexpr const char* thermalModeInterface =
1241 "xyz.openbmc_project.Control.ThermalMode";
1242constexpr const char* thermalModePath =
1243 "/xyz/openbmc_project/control/thermal_mode";
1244
1245bool getFanProfileInterface(
1246 sdbusplus::bus::bus& bus,
1247 boost::container::flat_map<
1248 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1249{
1250 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1251 "GetAll");
1252 call.append(thermalModeInterface);
1253 try
1254 {
1255 auto data = bus.call(call);
1256 data.read(resp);
1257 }
1258 catch (sdbusplus::exception_t& e)
1259 {
1260 phosphor::logging::log<phosphor::logging::level::ERR>(
1261 "getFanProfileInterface: can't get thermal mode!",
1262 phosphor::logging::entry("ERR=%s", e.what()));
1263 return false;
1264 }
1265 return true;
1266}
1267
1268ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1269 ipmi_request_t request, ipmi_response_t response,
1270 ipmi_data_len_t dataLen, ipmi_context_t context)
1271{
1272
1273 if (*dataLen < 2 || *dataLen > 7)
1274 {
1275 phosphor::logging::log<phosphor::logging::level::ERR>(
1276 "ipmiOEMSetFanConfig: invalid input len!");
1277 *dataLen = 0;
1278 return IPMI_CC_REQ_DATA_LEN_INVALID;
1279 }
1280
1281 // todo: tell bios to only send first 2 bytes
1282
1283 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1284 boost::container::flat_map<
1285 std::string, std::variant<std::vector<std::string>, std::string>>
1286 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001287 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1288 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001289 {
1290 return IPMI_CC_UNSPECIFIED_ERROR;
1291 }
1292
1293 std::vector<std::string>* supported =
1294 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1295 if (supported == nullptr)
1296 {
1297 return IPMI_CC_INVALID_FIELD_REQUEST;
1298 }
1299 std::string mode;
1300 if (req->flags &
1301 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1302 {
1303 bool performanceMode =
1304 (req->flags & (1 << static_cast<uint8_t>(
1305 setFanProfileFlags::performAcousSelect))) > 0;
1306
1307 if (performanceMode)
1308 {
1309
1310 if (std::find(supported->begin(), supported->end(),
1311 "Performance") != supported->end())
1312 {
1313 mode = "Performance";
1314 }
1315 }
1316 else
1317 {
1318
1319 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1320 supported->end())
1321 {
1322 mode = "Acoustic";
1323 }
1324 }
1325 if (mode.empty())
1326 {
1327 return IPMI_CC_INVALID_FIELD_REQUEST;
1328 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001329 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001330 thermalModeInterface, "Current", mode);
1331 }
1332
1333 return IPMI_CC_OK;
1334}
1335
James Feist5b693632019-07-09 09:06:09 -07001336ipmi::RspType<uint8_t, // profile support map
1337 uint8_t, // fan control profile enable
1338 uint8_t, // flags
1339 uint32_t // dimm presence bit map
1340 >
1341 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001342{
James Feist91244a62019-02-19 15:04:54 -08001343 boost::container::flat_map<
1344 std::string, std::variant<std::vector<std::string>, std::string>>
1345 profileData;
1346
Vernon Mauery15419dd2019-05-24 09:40:30 -07001347 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1348 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001349 {
James Feist5b693632019-07-09 09:06:09 -07001350 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001351 }
1352
1353 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1354
1355 if (current == nullptr)
1356 {
1357 phosphor::logging::log<phosphor::logging::level::ERR>(
1358 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001359 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001360 }
1361 bool performance = (*current == "Performance");
1362
James Feist5b693632019-07-09 09:06:09 -07001363 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001364 if (performance)
1365 {
James Feist5b693632019-07-09 09:06:09 -07001366 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001367 }
1368
James Feist5b693632019-07-09 09:06:09 -07001369 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001370}
James Feist5f957ca2019-03-14 15:33:55 -07001371constexpr const char* cfmLimitSettingPath =
1372 "/xyz/openbmc_project/control/cfm_limit";
1373constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001374constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001375constexpr const size_t legacyPCHSensorNumber = 0x22;
1376constexpr const char* exitAirPathName = "Exit_Air";
1377constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001378constexpr const char* pidConfigurationIface =
1379 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001380
James Feist09f6b602019-08-08 11:30:03 -07001381static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001382{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001383 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001384 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001385 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1386 "/xyz/openbmc_project/object_mapper",
1387 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001388
James Feistacc8a4e2019-04-02 14:23:57 -07001389 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001390 std::string path;
1391 GetSubTreeType resp;
1392 try
1393 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001394 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001395 reply.read(resp);
1396 }
1397 catch (sdbusplus::exception_t&)
1398 {
1399 phosphor::logging::log<phosphor::logging::level::ERR>(
1400 "ipmiOEMGetFscParameter: mapper error");
1401 };
James Feist09f6b602019-08-08 11:30:03 -07001402 auto config =
1403 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1404 return pair.first.find(name) != std::string::npos;
1405 });
James Feistfaa4f222019-03-21 16:21:55 -07001406 if (config != resp.end())
1407 {
1408 path = std::move(config->first);
1409 }
1410 return path;
1411}
James Feist5f957ca2019-03-14 15:33:55 -07001412
James Feistacc8a4e2019-04-02 14:23:57 -07001413// flat map to make alphabetical
1414static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1415{
1416 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001417 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001418 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001419 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1420 "/xyz/openbmc_project/object_mapper",
1421 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001422
1423 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1424 GetSubTreeType resp;
1425
1426 try
1427 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001428 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001429 reply.read(resp);
1430 }
1431 catch (sdbusplus::exception_t&)
1432 {
1433 phosphor::logging::log<phosphor::logging::level::ERR>(
1434 "getFanConfigPaths: mapper error");
1435 };
1436 for (const auto& [path, objects] : resp)
1437 {
1438 if (objects.empty())
1439 {
1440 continue; // should be impossible
1441 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001442
1443 try
1444 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001445 ret.emplace(path,
1446 getAllDbusProperties(*dbus, objects[0].first, path,
1447 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001448 }
1449 catch (sdbusplus::exception_t& e)
1450 {
1451 phosphor::logging::log<phosphor::logging::level::ERR>(
1452 "getPidConfigs: can't get DbusProperties!",
1453 phosphor::logging::entry("ERR=%s", e.what()));
1454 }
James Feistacc8a4e2019-04-02 14:23:57 -07001455 }
1456 return ret;
1457}
1458
1459ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1460{
1461 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1462 if (data.empty())
1463 {
1464 return ipmi::responseResponseError();
1465 }
1466 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1467 for (const auto& [_, pid] : data)
1468 {
1469 auto findClass = pid.find("Class");
1470 if (findClass == pid.end())
1471 {
1472 phosphor::logging::log<phosphor::logging::level::ERR>(
1473 "ipmiOEMGetFscParameter: found illegal pid "
1474 "configurations");
1475 return ipmi::responseResponseError();
1476 }
1477 std::string type = std::get<std::string>(findClass->second);
1478 if (type == "fan")
1479 {
1480 auto findOutLimit = pid.find("OutLimitMin");
1481 if (findOutLimit == pid.end())
1482 {
1483 phosphor::logging::log<phosphor::logging::level::ERR>(
1484 "ipmiOEMGetFscParameter: found illegal pid "
1485 "configurations");
1486 return ipmi::responseResponseError();
1487 }
1488 // get the min out of all the offsets
1489 minOffset = std::min(
1490 minOffset,
1491 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1492 }
1493 }
1494 if (minOffset == std::numeric_limits<uint8_t>::max())
1495 {
1496 phosphor::logging::log<phosphor::logging::level::ERR>(
1497 "ipmiOEMGetFscParameter: found no fan configurations!");
1498 return ipmi::responseResponseError();
1499 }
1500
1501 return ipmi::responseSuccess(minOffset);
1502}
1503
1504ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1505{
1506 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1507 if (data.empty())
1508 {
1509
1510 phosphor::logging::log<phosphor::logging::level::ERR>(
1511 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1512 return ipmi::responseResponseError();
1513 }
1514
Vernon Mauery15419dd2019-05-24 09:40:30 -07001515 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001516 bool found = false;
1517 for (const auto& [path, pid] : data)
1518 {
1519 auto findClass = pid.find("Class");
1520 if (findClass == pid.end())
1521 {
1522
1523 phosphor::logging::log<phosphor::logging::level::ERR>(
1524 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1525 "configurations");
1526 return ipmi::responseResponseError();
1527 }
1528 std::string type = std::get<std::string>(findClass->second);
1529 if (type == "fan")
1530 {
1531 auto findOutLimit = pid.find("OutLimitMin");
1532 if (findOutLimit == pid.end())
1533 {
1534
1535 phosphor::logging::log<phosphor::logging::level::ERR>(
1536 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1537 "configurations");
1538 return ipmi::responseResponseError();
1539 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001540 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001541 path, pidConfigurationIface, "OutLimitMin",
1542 static_cast<double>(offset));
1543 found = true;
1544 }
1545 }
1546 if (!found)
1547 {
1548 phosphor::logging::log<phosphor::logging::level::ERR>(
1549 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1550 return ipmi::responseResponseError();
1551 }
1552
1553 return ipmi::responseSuccess();
1554}
1555
1556ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1557 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001558{
1559 constexpr const size_t disableLimiting = 0x0;
1560
Vernon Mauery15419dd2019-05-24 09:40:30 -07001561 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001562 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001563 {
James Feist09f6b602019-08-08 11:30:03 -07001564 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001565 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001566 {
James Feist09f6b602019-08-08 11:30:03 -07001567 pathName = exitAirPathName;
1568 }
1569 else if (param1 == legacyPCHSensorNumber)
1570 {
1571 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001572 }
1573 else
1574 {
James Feistacc8a4e2019-04-02 14:23:57 -07001575 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001576 }
James Feist09f6b602019-08-08 11:30:03 -07001577 std::string path = getConfigPath(pathName);
1578 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1579 pidConfigurationIface, "SetPoint",
1580 static_cast<double>(param2));
1581 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001582 }
James Feistacc8a4e2019-04-02 14:23:57 -07001583 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001584 {
James Feistacc8a4e2019-04-02 14:23:57 -07001585 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001586
1587 // must be greater than 50 based on eps
1588 if (cfm < 50 && cfm != disableLimiting)
1589 {
James Feistacc8a4e2019-04-02 14:23:57 -07001590 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001591 }
1592
1593 try
1594 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001595 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001596 cfmLimitIface, "Limit",
1597 static_cast<double>(cfm));
1598 }
1599 catch (sdbusplus::exception_t& e)
1600 {
1601 phosphor::logging::log<phosphor::logging::level::ERR>(
1602 "ipmiOEMSetFscParameter: can't set cfm setting!",
1603 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001604 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001605 }
James Feistacc8a4e2019-04-02 14:23:57 -07001606 return ipmi::responseSuccess();
1607 }
1608 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1609 {
1610 constexpr const size_t maxDomainCount = 8;
1611 uint8_t requestedDomainMask = param1;
1612 boost::container::flat_map data = getPidConfigs();
1613 if (data.empty())
1614 {
1615
1616 phosphor::logging::log<phosphor::logging::level::ERR>(
1617 "ipmiOEMSetFscParameter: found no pid configurations!");
1618 return ipmi::responseResponseError();
1619 }
1620 size_t count = 0;
1621 for (const auto& [path, pid] : data)
1622 {
1623 auto findClass = pid.find("Class");
1624 if (findClass == pid.end())
1625 {
1626
1627 phosphor::logging::log<phosphor::logging::level::ERR>(
1628 "ipmiOEMSetFscParameter: found illegal pid "
1629 "configurations");
1630 return ipmi::responseResponseError();
1631 }
1632 std::string type = std::get<std::string>(findClass->second);
1633 if (type == "fan")
1634 {
1635 if (requestedDomainMask & (1 << count))
1636 {
1637 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001638 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001639 pidConfigurationIface, "OutLimitMax",
1640 static_cast<double>(param2));
1641 }
1642 count++;
1643 }
1644 }
1645 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001646 }
1647 else
1648 {
1649 // todo other command parts possibly
1650 // tcontrol is handled in peci now
1651 // fan speed offset not implemented yet
1652 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001653 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001654 }
1655}
1656
James Feistacc8a4e2019-04-02 14:23:57 -07001657ipmi::RspType<
1658 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1659 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001660{
James Feist09f6b602019-08-08 11:30:03 -07001661 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001662
Vernon Mauery15419dd2019-05-24 09:40:30 -07001663 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001664 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001665 {
James Feistacc8a4e2019-04-02 14:23:57 -07001666 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001667 {
James Feistacc8a4e2019-04-02 14:23:57 -07001668 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001669 }
1670
James Feist09f6b602019-08-08 11:30:03 -07001671 std::string pathName;
1672
1673 if (*param == legacyExitAirSensorNumber)
1674 {
1675 pathName = exitAirPathName;
1676 }
1677 else if (*param == legacyPCHSensorNumber)
1678 {
1679 pathName = pchPathName;
1680 }
1681 else
James Feistfaa4f222019-03-21 16:21:55 -07001682 {
James Feistacc8a4e2019-04-02 14:23:57 -07001683 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001684 }
James Feist09f6b602019-08-08 11:30:03 -07001685
1686 uint8_t setpoint = legacyDefaultSetpoint;
1687 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001688 if (path.size())
1689 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001690 Value val = ipmi::getDbusProperty(
1691 *dbus, "xyz.openbmc_project.EntityManager", path,
1692 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001693 setpoint = std::floor(std::get<double>(val) + 0.5);
1694 }
1695
1696 // old implementation used to return the "default" and current, we
1697 // don't make the default readily available so just make both the
1698 // same
James Feistfaa4f222019-03-21 16:21:55 -07001699
James Feistacc8a4e2019-04-02 14:23:57 -07001700 return ipmi::responseSuccess(
1701 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001702 }
James Feistacc8a4e2019-04-02 14:23:57 -07001703 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1704 {
1705 constexpr const size_t maxDomainCount = 8;
1706
1707 if (!param)
1708 {
1709 return ipmi::responseReqDataLenInvalid();
1710 }
1711 uint8_t requestedDomain = *param;
1712 if (requestedDomain >= maxDomainCount)
1713 {
1714 return ipmi::responseInvalidFieldRequest();
1715 }
1716
1717 boost::container::flat_map data = getPidConfigs();
1718 if (data.empty())
1719 {
1720 phosphor::logging::log<phosphor::logging::level::ERR>(
1721 "ipmiOEMGetFscParameter: found no pid configurations!");
1722 return ipmi::responseResponseError();
1723 }
1724 size_t count = 0;
1725 for (const auto& [_, pid] : data)
1726 {
1727 auto findClass = pid.find("Class");
1728 if (findClass == pid.end())
1729 {
1730 phosphor::logging::log<phosphor::logging::level::ERR>(
1731 "ipmiOEMGetFscParameter: found illegal pid "
1732 "configurations");
1733 return ipmi::responseResponseError();
1734 }
1735 std::string type = std::get<std::string>(findClass->second);
1736 if (type == "fan")
1737 {
1738 if (requestedDomain == count)
1739 {
1740 auto findOutLimit = pid.find("OutLimitMax");
1741 if (findOutLimit == pid.end())
1742 {
1743 phosphor::logging::log<phosphor::logging::level::ERR>(
1744 "ipmiOEMGetFscParameter: found illegal pid "
1745 "configurations");
1746 return ipmi::responseResponseError();
1747 }
1748
1749 return ipmi::responseSuccess(
1750 static_cast<uint8_t>(std::floor(
1751 std::get<double>(findOutLimit->second) + 0.5)));
1752 }
1753 else
1754 {
1755 count++;
1756 }
1757 }
1758 }
1759
1760 return ipmi::responseInvalidFieldRequest();
1761 }
1762 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001763 {
1764
1765 /*
1766 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001767 previous behavior didn't seem to prevent this, ignore the check for
1768 now.
James Feist5f957ca2019-03-14 15:33:55 -07001769
James Feistacc8a4e2019-04-02 14:23:57 -07001770 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001771 {
1772 phosphor::logging::log<phosphor::logging::level::ERR>(
1773 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001774 return IPMI_CC_REQ_DATA_LEN_INVALID;
1775 }
1776 */
1777 Value cfmLimit;
1778 Value cfmMaximum;
1779 try
1780 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001781 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001782 cfmLimitSettingPath, cfmLimitIface,
1783 "Limit");
1784 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001785 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001786 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1787 }
1788 catch (sdbusplus::exception_t& e)
1789 {
1790 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001791 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001792 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001793 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001794 }
1795
James Feistacc8a4e2019-04-02 14:23:57 -07001796 double cfmMax = std::get<double>(cfmMaximum);
1797 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001798
James Feistacc8a4e2019-04-02 14:23:57 -07001799 cfmLim = std::floor(cfmLim + 0.5);
1800 cfmMax = std::floor(cfmMax + 0.5);
1801 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1802 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001803
James Feistacc8a4e2019-04-02 14:23:57 -07001804 return ipmi::responseSuccess(
1805 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001806 }
James Feistacc8a4e2019-04-02 14:23:57 -07001807
James Feist5f957ca2019-03-14 15:33:55 -07001808 else
1809 {
1810 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001811 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001812 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001813 }
1814}
1815
Cheng C Yang773703a2019-08-15 09:41:11 +08001816using crConfigVariant =
1817 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
1818
1819int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1820 const crConfigVariant& value,
1821 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1822{
1823 boost::system::error_code ec;
1824 ctx->bus->yield_method_call<void>(
1825 *(ctx->yield), ec, "xyz.openbmc_project.Settings",
1826 "/xyz/openbmc_project/control/power_supply_redundancy",
1827 "org.freedesktop.DBus.Properties", "Set",
1828 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
1829 if (ec)
1830 {
1831 phosphor::logging::log<phosphor::logging::level::ERR>(
1832 "Failed to set dbus property to cold redundancy");
1833 return -1;
1834 }
1835
1836 return 0;
1837}
1838
1839int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1840 crConfigVariant& value,
1841 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1842{
1843 boost::system::error_code ec;
1844 value = ctx->bus->yield_method_call<crConfigVariant>(
1845 *(ctx->yield), ec, "xyz.openbmc_project.Settings",
1846 "/xyz/openbmc_project/control/power_supply_redundancy",
1847 "org.freedesktop.DBus.Properties", "Get",
1848 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
1849 if (ec)
1850 {
1851 phosphor::logging::log<phosphor::logging::level::ERR>(
1852 "Failed to get dbus property to cold redundancy");
1853 return -1;
1854 }
1855 return 0;
1856}
1857
1858uint8_t getPSUCount(void)
1859{
1860 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1861 ipmi::Value num;
1862 try
1863 {
1864 num = ipmi::getDbusProperty(
1865 *dbus, "xyz.openbmc_project.PSURedundancy",
1866 "/xyz/openbmc_project/control/power_supply_redundancy",
1867 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
1868 }
1869 catch (sdbusplus::exception_t& e)
1870 {
1871 phosphor::logging::log<phosphor::logging::level::ERR>(
1872 "Failed to get PSUNumber property from dbus interface");
1873 return 0;
1874 }
1875 uint8_t* pNum = std::get_if<uint8_t>(&num);
1876 if (!pNum)
1877 {
1878 phosphor::logging::log<phosphor::logging::level::ERR>(
1879 "Error to get PSU Number");
1880 return 0;
1881 }
1882 return *pNum;
1883}
1884
1885bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
1886{
1887 if (conf.size() < num)
1888 {
1889 phosphor::logging::log<phosphor::logging::level::ERR>(
1890 "Invalid PSU Ranking");
1891 return false;
1892 }
1893 std::set<uint8_t> confSet;
1894 for (uint8_t i = 0; i < num; i++)
1895 {
1896 if (conf[i] > num)
1897 {
1898 phosphor::logging::log<phosphor::logging::level::ERR>(
1899 "PSU Ranking is larger than current PSU number");
1900 return false;
1901 }
1902 confSet.emplace(conf[i]);
1903 }
1904
1905 if (confSet.size() != num)
1906 {
1907 phosphor::logging::log<phosphor::logging::level::ERR>(
1908 "duplicate PSU Ranking");
1909 return false;
1910 }
1911 return true;
1912}
1913
1914enum class crParameter
1915{
1916 crStatus = 0,
1917 crFeature = 1,
1918 rotationFeature = 2,
1919 rotationAlgo = 3,
1920 rotationPeriod = 4,
1921 numOfPSU = 5
1922};
1923
1924constexpr ipmi::Cc ccParameterNotSupported = 0x80;
1925static const constexpr uint32_t oneDay = 0x15180;
1926static const constexpr uint32_t oneMonth = 0xf53700;
1927static const constexpr uint8_t userSpecific = 0x01;
1928static const constexpr uint8_t crSetCompleted = 0;
1929ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
1930 uint8_t parameter,
1931 ipmi::message::Payload& payload)
1932{
1933 switch (static_cast<crParameter>(parameter))
1934 {
1935 case crParameter::crFeature:
1936 {
1937 uint8_t param1;
1938 if (payload.unpack(param1) || !payload.fullyUnpacked())
1939 {
1940 return ipmi::responseReqDataLenInvalid();
1941 }
1942 // ColdRedundancy Enable can only be true or flase
1943 if (param1 > 1)
1944 {
1945 return ipmi::responseInvalidFieldRequest();
1946 }
1947 if (setCRConfig(ctx, "ColdRedundancyEnabled",
1948 static_cast<bool>(param1)))
1949 {
1950 return ipmi::responseResponseError();
1951 }
1952 break;
1953 }
1954 case crParameter::rotationFeature:
1955 {
1956 uint8_t param1;
1957 if (payload.unpack(param1) || !payload.fullyUnpacked())
1958 {
1959 return ipmi::responseReqDataLenInvalid();
1960 }
1961 // Rotation Enable can only be true or false
1962 if (param1 > 1)
1963 {
1964 return ipmi::responseInvalidFieldRequest();
1965 }
1966 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
1967 {
1968 return ipmi::responseResponseError();
1969 }
1970 break;
1971 }
1972 case crParameter::rotationAlgo:
1973 {
1974 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
1975 std::string algoName;
1976 uint8_t param1;
1977 if (payload.unpack(param1))
1978 {
1979 return ipmi::responseReqDataLenInvalid();
1980 }
1981 switch (param1)
1982 {
1983 case 0:
1984 algoName = "xyz.openbmc_project.Control."
1985 "PowerSupplyRedundancy.Algo.bmcSpecific";
1986 break;
1987 case 1:
1988 algoName = "xyz.openbmc_project.Control."
1989 "PowerSupplyRedundancy.Algo.userSpecific";
1990 break;
1991 default:
1992 return ipmi::responseInvalidFieldRequest();
1993 }
1994 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
1995 {
1996 return ipmi::responseResponseError();
1997 }
1998
1999 uint8_t numberOfPSU = getPSUCount();
2000 if (!numberOfPSU)
2001 {
2002 return ipmi::responseResponseError();
2003 }
2004 std::vector<uint8_t> rankOrder;
2005
2006 if (param1 == userSpecific)
2007 {
2008 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
2009 {
2010 ipmi::responseReqDataLenInvalid();
2011 }
2012 if (rankOrder.size() < numberOfPSU)
2013 {
2014 return ipmi::responseReqDataLenInvalid();
2015 }
2016
2017 if (!validateCRAlgo(rankOrder, numberOfPSU))
2018 {
2019 return ipmi::responseInvalidFieldRequest();
2020 }
2021 }
2022 else
2023 {
2024 if (rankOrder.size() > 0)
2025 {
2026 return ipmi::responseReqDataLenInvalid();
2027 }
2028 for (uint8_t i = 1; i <= numberOfPSU; i++)
2029 {
2030 rankOrder.emplace_back(i);
2031 }
2032 }
2033 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
2034 {
2035 return ipmi::responseResponseError();
2036 }
2037 break;
2038 }
2039 case crParameter::rotationPeriod:
2040 {
2041 // Minimum Rotation period is One day (86400 seconds) and Max
2042 // Rotation Period is 6 month (0xf53700 seconds)
2043 uint32_t period;
2044 if (payload.unpack(period) || !payload.fullyUnpacked())
2045 {
2046 return ipmi::responseReqDataLenInvalid();
2047 }
2048 if ((period < oneDay) || (period > oneMonth))
2049 {
2050 return ipmi::responseInvalidFieldRequest();
2051 }
2052 if (setCRConfig(ctx, "PeriodOfRotation", period))
2053 {
2054 return ipmi::responseResponseError();
2055 }
2056 break;
2057 }
2058 default:
2059 {
2060 return ipmi::response(ccParameterNotSupported);
2061 }
2062 }
2063
2064 // TODO Halfwidth needs to set SetInProgress
2065 if (setCRConfig(ctx, "ColdRedundancyStatus",
2066 "xyz.openbmc_project.Control.PowerSupplyRedundancy.Status."
2067 "completed"))
2068 {
2069 return ipmi::responseResponseError();
2070 }
2071 return ipmi::responseSuccess(crSetCompleted);
2072}
2073
2074ipmi::RspType<std::variant<uint8_t, uint32_t, std::array<uint8_t, 5>>>
2075 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2076{
2077 crConfigVariant value;
2078 switch (static_cast<crParameter>(parameter))
2079 {
2080 case crParameter::crStatus:
2081 {
2082 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2083 {
2084 return ipmi::responseResponseError();
2085 }
2086 std::string* pStatus = std::get_if<std::string>(&value);
2087 if (!pStatus)
2088 {
2089 phosphor::logging::log<phosphor::logging::level::ERR>(
2090 "Error to get ColdRedundancyStatus property");
2091 return ipmi::responseResponseError();
2092 }
2093 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2094 auto status =
2095 server::PowerSupplyRedundancy::convertStatusFromString(
2096 *pStatus);
2097 switch (status)
2098 {
2099 case server::PowerSupplyRedundancy::Status::inProgress:
2100 return ipmi::responseSuccess(static_cast<uint8_t>(0));
2101
2102 case server::PowerSupplyRedundancy::Status::completed:
2103 return ipmi::responseSuccess(static_cast<uint8_t>(1));
2104 default:
2105 phosphor::logging::log<phosphor::logging::level::ERR>(
2106 "Error to get valid status");
2107 return ipmi::responseResponseError();
2108 }
2109 }
2110 case crParameter::crFeature:
2111 {
2112 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2113 {
2114 return ipmi::responseResponseError();
2115 }
2116 bool* pResponse = std::get_if<bool>(&value);
2117 if (!pResponse)
2118 {
2119 phosphor::logging::log<phosphor::logging::level::ERR>(
2120 "Error to get ColdRedundancyEnable property");
2121 return ipmi::responseResponseError();
2122 }
2123
2124 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse));
2125 }
2126 case crParameter::rotationFeature:
2127 {
2128 if (getCRConfig(ctx, "RotationEnabled", value))
2129 {
2130 return ipmi::responseResponseError();
2131 }
2132 bool* pResponse = std::get_if<bool>(&value);
2133 if (!pResponse)
2134 {
2135 phosphor::logging::log<phosphor::logging::level::ERR>(
2136 "Error to get RotationEnabled property");
2137 return ipmi::responseResponseError();
2138 }
2139 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse));
2140 }
2141 case crParameter::rotationAlgo:
2142 {
2143 if (getCRConfig(ctx, "RotationAlgorithm", value))
2144 {
2145 return ipmi::responseResponseError();
2146 }
2147
2148 std::string* pAlgo = std::get_if<std::string>(&value);
2149 if (!pAlgo)
2150 {
2151 phosphor::logging::log<phosphor::logging::level::ERR>(
2152 "Error to get RotationAlgorithm property");
2153 return ipmi::responseResponseError();
2154 }
2155 std::array<uint8_t, 5> response = {0, 0, 0, 0, 0};
2156 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2157 auto algo =
2158 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
2159 switch (algo)
2160 {
2161 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
2162 response[0] = 0;
2163 break;
2164 case server::PowerSupplyRedundancy::Algo::userSpecific:
2165 response[0] = 1;
2166 break;
2167 default:
2168 phosphor::logging::log<phosphor::logging::level::ERR>(
2169 "Error to get valid algo");
2170 return ipmi::responseResponseError();
2171 }
2172
2173 if (getCRConfig(ctx, "RotationRankOrder", value))
2174 {
2175 return ipmi::responseResponseError();
2176 }
2177 std::vector<uint8_t>* pResponse =
2178 std::get_if<std::vector<uint8_t>>(&value);
2179 if (!pResponse)
2180 {
2181 phosphor::logging::log<phosphor::logging::level::ERR>(
2182 "Error to get RotationRankOrder property");
2183 return ipmi::responseResponseError();
2184 }
2185 if (pResponse->size() + 1 > response.size())
2186 {
2187 phosphor::logging::log<phosphor::logging::level::ERR>(
2188 "Incorrect size of RotationAlgorithm property");
2189 return ipmi::responseResponseError();
2190 }
2191 std::copy(pResponse->begin(), pResponse->end(),
2192 response.begin() + 1);
2193 return ipmi::responseSuccess(response);
2194 }
2195 case crParameter::rotationPeriod:
2196 {
2197 if (getCRConfig(ctx, "PeriodOfRotation", value))
2198 {
2199 return ipmi::responseResponseError();
2200 }
2201 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2202 if (!pResponse)
2203 {
2204 phosphor::logging::log<phosphor::logging::level::ERR>(
2205 "Error to get RotationAlgorithm property");
2206 return ipmi::responseResponseError();
2207 }
2208 return ipmi::responseSuccess(*pResponse);
2209 }
2210 case crParameter::numOfPSU:
2211 {
2212 uint8_t numberOfPSU = getPSUCount();
2213 if (!numberOfPSU)
2214 {
2215 return ipmi::responseResponseError();
2216 }
2217 return ipmi::responseSuccess(numberOfPSU);
2218 }
2219 default:
2220 {
2221 return ipmi::response(ccParameterNotSupported);
2222 }
2223 }
2224}
2225
Zhu, Yungebe560b02019-04-21 21:19:21 -04002226ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2227 uint8_t faultState,
2228 uint8_t faultGroup,
2229 std::array<uint8_t, 8>& ledStateData)
2230{
2231 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2232 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2233 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2234 static const std::array<std::string, maxFaultType> faultNames = {
2235 "faultFan", "faultTemp", "faultPower",
2236 "faultDriveSlot", "faultSoftware", "faultMemory"};
2237 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2238 static constexpr const char* postfixValue = "/value";
2239
2240 constexpr uint8_t maxFaultSource = 0x4;
2241 constexpr uint8_t skipLEDs = 0xFF;
2242 constexpr uint8_t pinSize = 64;
2243 constexpr uint8_t groupSize = 16;
2244
2245 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2246 uint64_t resFIndex = 0;
2247 std::string resFType;
2248 std::string service;
2249 ObjectValueTree valueTree;
2250
2251 // Validate the source, fault type
2252 if ((sourceId >= maxFaultSource) ||
2253 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2254 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2255 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2256 {
2257 return ipmi::responseParmOutOfRange();
2258 }
2259
Vernon Mauery15419dd2019-05-24 09:40:30 -07002260 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002261 try
2262 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002263 service = getService(*dbus, intf, objpath);
2264 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002265 }
2266 catch (const std::exception& e)
2267 {
2268 phosphor::logging::log<phosphor::logging::level::ERR>(
2269 "No object implements interface",
2270 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2271 phosphor::logging::entry("INTF=%s", intf));
2272 return ipmi::responseResponseError();
2273 }
2274
2275 if (valueTree.empty())
2276 {
2277 phosphor::logging::log<phosphor::logging::level::ERR>(
2278 "No object implements interface",
2279 phosphor::logging::entry("INTF=%s", intf));
2280 return ipmi::responseResponseError();
2281 }
2282
2283 for (const auto& item : valueTree)
2284 {
2285 // find LedFault configuration
2286 auto interface =
2287 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2288 if (interface == item.second.end())
2289 {
2290 continue;
2291 }
2292
2293 // find matched fault type: faultMemmory / faultFan
2294 // find LedGpioPins/FaultIndex configuration
2295 auto propertyFaultType = interface->second.find("FaultType");
2296 auto propertyFIndex = interface->second.find("FaultIndex");
2297 auto ledIndex = interface->second.find("LedGpioPins");
2298
2299 if (propertyFaultType == interface->second.end() ||
2300 propertyFIndex == interface->second.end() ||
2301 ledIndex == interface->second.end())
2302 {
2303 continue;
2304 }
2305
2306 try
2307 {
2308 Value valIndex = propertyFIndex->second;
2309 resFIndex = std::get<uint64_t>(valIndex);
2310
2311 Value valFType = propertyFaultType->second;
2312 resFType = std::get<std::string>(valFType);
2313 }
2314 catch (const std::bad_variant_access& e)
2315 {
2316 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2317 return ipmi::responseResponseError();
2318 }
2319 // find the matched requested fault type: faultMemmory or faultFan
2320 if (resFType != faultNames[faultType])
2321 {
2322 continue;
2323 }
2324
2325 // read LedGpioPins data
2326 std::vector<uint64_t> ledgpios;
2327 std::variant<std::vector<uint64_t>> message;
2328
Vernon Mauery15419dd2019-05-24 09:40:30 -07002329 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002330 service.c_str(), (std::string(item.first)).c_str(),
2331 "org.freedesktop.DBus.Properties", "Get");
2332
2333 method.append("xyz.openbmc_project.Configuration.LedFault",
2334 "LedGpioPins");
2335
2336 try
2337 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002338 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002339 reply.read(message);
2340 ledgpios = std::get<std::vector<uint64_t>>(message);
2341 }
2342 catch (std::exception& e)
2343 {
2344 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2345 return ipmi::responseResponseError();
2346 }
2347
2348 // Check the size to be sure it will never overflow on groupSize
2349 if (ledgpios.size() > groupSize)
2350 {
2351 phosphor::logging::log<phosphor::logging::level::ERR>(
2352 "Fault gpio Pins out of range!");
2353 return ipmi::responseParmOutOfRange();
2354 }
2355 // Store data, according to command data bit index order
2356 for (int i = 0; i < ledgpios.size(); i++)
2357 {
2358 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2359 }
2360 }
2361
2362 switch (RemoteFaultType(faultType))
2363 {
2364 case (RemoteFaultType::fan):
2365 case (RemoteFaultType::memory):
2366 {
2367 if (faultGroup == skipLEDs)
2368 {
2369 return ipmi::responseSuccess();
2370 }
2371
2372 uint64_t ledState = 0;
2373 // calculate led state bit filed count, each byte has 8bits
2374 // the maximum bits will be 8 * 8 bits
2375 constexpr uint8_t size = sizeof(ledStateData) * 8;
2376 for (int i = 0; i < sizeof(ledStateData); i++)
2377 {
2378 ledState = (uint64_t)(ledState << 8);
2379 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2380 }
2381
2382 std::bitset<size> ledStateBits(ledState);
2383 std::string gpioValue;
2384 for (int i = 0; i < size; i++)
2385 { // skip invalid value
2386 if (ledFaultPins[i] == 0xFFFF)
2387 {
2388 continue;
2389 }
2390
2391 std::string device = sysGpioPath +
2392 std::to_string(ledFaultPins[i]) +
2393 postfixValue;
2394 std::fstream gpioFile;
2395
2396 gpioFile.open(device, std::ios::out);
2397
2398 if (!gpioFile.good())
2399 {
2400 phosphor::logging::log<phosphor::logging::level::ERR>(
2401 "Not Find Led Gpio Device!",
2402 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2403 return ipmi::responseResponseError();
2404 }
2405 gpioFile << std::to_string(
2406 static_cast<uint8_t>(ledStateBits[i]));
2407 gpioFile.close();
2408 }
2409 break;
2410 }
2411 default:
2412 {
2413 // now only support two fault types
2414 return ipmi::responseParmOutOfRange();
2415 }
2416 }
2417
2418 return ipmi::responseSuccess();
2419}
2420
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302421ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2422{
2423 uint8_t prodId = 0;
2424 try
2425 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002426 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302427 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002428 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302429 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2430 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002431 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302432 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2433 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2434 }
2435 catch (std::exception& e)
2436 {
2437 phosphor::logging::log<phosphor::logging::level::ERR>(
2438 "ipmiOEMReadBoardProductId: Product ID read failed!",
2439 phosphor::logging::entry("ERR=%s", e.what()));
2440 }
2441 return ipmi::responseSuccess(prodId);
2442}
2443
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002444ipmi::RspType<uint8_t /* restore status */>
2445 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2446{
2447 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2448
2449 if (clr != expClr)
2450 {
2451 return ipmi::responseInvalidFieldRequest();
2452 }
2453 constexpr uint8_t cmdStatus = 0;
2454 constexpr uint8_t cmdDefaultRestore = 0xaa;
2455 constexpr uint8_t cmdFullRestore = 0xbb;
2456 constexpr uint8_t cmdFormat = 0xcc;
2457
2458 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2459
2460 switch (cmd)
2461 {
2462 case cmdStatus:
2463 break;
2464 case cmdDefaultRestore:
2465 case cmdFullRestore:
2466 case cmdFormat:
2467 {
2468 // write file to rwfs root
2469 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2470 std::ofstream restoreFile(restoreOpFname);
2471 if (!restoreFile)
2472 {
2473 return ipmi::responseUnspecifiedError();
2474 }
2475 restoreFile << value << "\n";
2476 break;
2477 }
2478 default:
2479 return ipmi::responseInvalidFieldRequest();
2480 }
2481
2482 constexpr uint8_t restorePending = 0;
2483 constexpr uint8_t restoreComplete = 1;
2484
2485 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2486 ? restorePending
2487 : restoreComplete;
2488 return ipmi::responseSuccess(restoreStatus);
2489}
2490
Chen Yugang39736d52019-07-12 16:24:33 +08002491ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2492{
2493 uint8_t bmcSource;
2494 namespace nmi = sdbusplus::com::intel::Control::server;
2495
2496 try
2497 {
2498 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2499 std::string service =
2500 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2501 Value variant =
2502 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2503 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2504
2505 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2506 std::get<std::string>(variant)))
2507 {
2508 case nmi::NMISource::BMCSourceSignal::None:
2509 bmcSource = static_cast<uint8_t>(NmiSource::none);
2510 break;
2511 case nmi::NMISource::BMCSourceSignal::FpBtn:
2512 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
2513 break;
2514 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
2515 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
2516 break;
2517 case nmi::NMISource::BMCSourceSignal::PefMatch:
2518 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
2519 break;
2520 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2521 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2522 break;
2523 case nmi::NMISource::BMCSourceSignal::MemoryError:
2524 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2525 break;
2526 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
2527 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
2528 break;
2529 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
2530 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
2531 break;
2532 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
2533 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
2534 break;
2535 default:
2536 phosphor::logging::log<phosphor::logging::level::ERR>(
2537 "NMI source: invalid property!",
2538 phosphor::logging::entry(
2539 "PROP=%s", std::get<std::string>(variant).c_str()));
2540 return ipmi::responseResponseError();
2541 }
2542 }
2543 catch (sdbusplus::exception::SdBusError& e)
2544 {
2545 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2546 return ipmi::responseResponseError();
2547 }
2548
2549 return ipmi::responseSuccess(bmcSource);
2550}
2551
2552ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2553{
2554 namespace nmi = sdbusplus::com::intel::Control::server;
2555
2556 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2557 nmi::NMISource::BMCSourceSignal::None;
2558
2559 switch (NmiSource(sourceId))
2560 {
2561 case NmiSource::none:
2562 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2563 break;
2564 case NmiSource::fpBtn:
2565 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2566 break;
2567 case NmiSource::wdPreTimeout:
2568 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2569 break;
2570 case NmiSource::pefMatch:
2571 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2572 break;
2573 case NmiSource::chassisCmd:
2574 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2575 break;
2576 case NmiSource::memoryError:
2577 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2578 break;
2579 case NmiSource::pciSerrPerr:
2580 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2581 break;
2582 case NmiSource::southbridgeNmi:
2583 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2584 break;
2585 case NmiSource::chipsetNmi:
2586 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2587 break;
2588 default:
2589 phosphor::logging::log<phosphor::logging::level::ERR>(
2590 "NMI source: invalid property!");
2591 return ipmi::responseResponseError();
2592 }
2593
2594 try
2595 {
2596 // keep NMI signal source
2597 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2598 std::string service =
2599 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2600 setDbusProperty(
2601 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2602 oemNmiBmcSourceObjPathProp,
2603 sdbusplus::com::intel::Control::server::convertForMessage(
2604 bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002605 // set Enabled property to inform NMI source handling
2606 // to trigger a NMI_OUT BSOD.
2607 // if it's triggered by NMI source property changed,
2608 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2609 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2610 {
2611 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2612 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2613 static_cast<bool>(true));
2614 }
Chen Yugang39736d52019-07-12 16:24:33 +08002615 }
2616 catch (sdbusplus::exception_t& e)
2617 {
2618 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2619 return ipmi::responseResponseError();
2620 }
2621
2622 return ipmi::responseSuccess();
2623}
2624
James Feist63efafa2019-07-24 12:39:21 -07002625namespace dimmOffset
2626{
2627constexpr const char* dimmPower = "DimmPower";
2628constexpr const char* staticCltt = "StaticCltt";
2629constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2630constexpr const char* offsetInterface =
2631 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2632constexpr const char* property = "DimmOffset";
2633
2634}; // namespace dimmOffset
2635
2636ipmi::RspType<>
2637 ipmiOEMSetDimmOffset(uint8_t type,
2638 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2639{
2640 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2641 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2642 {
2643 return ipmi::responseInvalidFieldRequest();
2644 }
2645
2646 if (data.empty())
2647 {
2648 return ipmi::responseInvalidFieldRequest();
2649 }
2650 nlohmann::json json;
2651
2652 std::ifstream jsonStream(dimmOffsetFile);
2653 if (jsonStream.good())
2654 {
2655 json = nlohmann::json::parse(jsonStream, nullptr, false);
2656 if (json.is_discarded())
2657 {
2658 json = nlohmann::json();
2659 }
2660 jsonStream.close();
2661 }
2662
2663 std::string typeName;
2664 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2665 {
2666 typeName = dimmOffset::dimmPower;
2667 }
2668 else
2669 {
2670 typeName = dimmOffset::staticCltt;
2671 }
2672
2673 nlohmann::json& field = json[typeName];
2674
2675 for (const auto& [index, value] : data)
2676 {
2677 field[index] = value;
2678 }
2679
2680 for (nlohmann::json& val : field)
2681 {
2682 if (val == nullptr)
2683 {
2684 val = static_cast<uint8_t>(0);
2685 }
2686 }
2687
2688 std::ofstream output(dimmOffsetFile);
2689 if (!output.good())
2690 {
2691 std::cerr << "Error writing json file\n";
2692 return ipmi::responseResponseError();
2693 }
2694
2695 output << json.dump(4);
2696
2697 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2698 {
2699 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
2700
2701 std::variant<std::vector<uint8_t>> offsets =
2702 field.get<std::vector<uint8_t>>();
2703 auto call = bus->new_method_call(
2704 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
2705 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
2706 try
2707 {
2708 bus->call(call);
2709 }
2710 catch (sdbusplus::exception_t& e)
2711 {
2712 phosphor::logging::log<phosphor::logging::level::ERR>(
2713 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
2714 phosphor::logging::entry("ERR=%s", e.what()));
2715 return ipmi::responseResponseError();
2716 }
2717 }
2718
2719 return ipmi::responseSuccess();
2720}
2721
2722ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
2723{
2724
2725 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2726 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2727 {
2728 return ipmi::responseInvalidFieldRequest();
2729 }
2730
2731 std::ifstream jsonStream(dimmOffsetFile);
2732
2733 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
2734 if (json.is_discarded())
2735 {
2736 std::cerr << "File error in " << dimmOffsetFile << "\n";
2737 return ipmi::responseResponseError();
2738 }
2739
2740 std::string typeName;
2741 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2742 {
2743 typeName = dimmOffset::dimmPower;
2744 }
2745 else
2746 {
2747 typeName = dimmOffset::staticCltt;
2748 }
2749
2750 auto it = json.find(typeName);
2751 if (it == json.end())
2752 {
2753 return ipmi::responseInvalidFieldRequest();
2754 }
2755
2756 if (it->size() <= index)
2757 {
2758 return ipmi::responseInvalidFieldRequest();
2759 }
2760
2761 uint8_t resp = it->at(index).get<uint8_t>();
2762 return ipmi::responseSuccess(resp);
2763}
2764
Jason M. Bills64796042018-10-03 16:51:55 -07002765static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002766{
2767 phosphor::logging::log<phosphor::logging::level::INFO>(
2768 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07002769 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
2770 ipmiOEMWildcard,
2771 PRIVILEGE_USER); // wildcard default handler
2772 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
2773 ipmiOEMWildcard,
2774 PRIVILEGE_USER); // wildcard default handler
2775 ipmiPrintAndRegister(
2776 netfnIntcOEMGeneral,
2777 static_cast<ipmi_cmd_t>(
2778 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
2779 NULL, ipmiOEMGetChassisIdentifier,
2780 PRIVILEGE_USER); // get chassis identifier
2781 ipmiPrintAndRegister(
2782 netfnIntcOEMGeneral,
2783 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
2784 NULL, ipmiOEMSetSystemGUID,
2785 PRIVILEGE_ADMIN); // set system guid
Jason M. Billsb02bf092019-08-15 13:01:56 -07002786
2787 // <Disable BMC System Reset Action>
2788 ipmi::registerHandler(
2789 ipmi::prioOemBase, netfnIntcOEMGeneral,
2790 static_cast<ipmi::Cmd>(
2791 IPMINetfnIntelOEMGeneralCmd::cmdDisableBMCSystemReset),
2792 ipmi::Privilege::Admin, ipmiOEMDisableBMCSystemReset);
2793 // <Get BMC Reset Disables>
2794 ipmi::registerHandler(
2795 ipmi::prioOemBase, netfnIntcOEMGeneral,
2796 static_cast<ipmi::Cmd>(
2797 IPMINetfnIntelOEMGeneralCmd::cmdGetBMCResetDisables),
2798 ipmi::Privilege::Admin, ipmiOEMGetBMCResetDisables);
2799
Jason M. Bills64796042018-10-03 16:51:55 -07002800 ipmiPrintAndRegister(
2801 netfnIntcOEMGeneral,
2802 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
2803 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
2804 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2805 static_cast<ipmi_cmd_t>(
2806 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
2807 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
2808 ipmiPrintAndRegister(
2809 netfnIntcOEMGeneral,
2810 static_cast<ipmi_cmd_t>(
2811 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
2812 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08002813
2814 ipmi::registerHandler(
2815 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2816 static_cast<ipmi::Cmd>(
2817 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
2818 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
2819
Jason M. Bills64796042018-10-03 16:51:55 -07002820 ipmiPrintAndRegister(
2821 netfnIntcOEMGeneral,
2822 static_cast<ipmi_cmd_t>(
2823 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
2824 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
2825 ipmiPrintAndRegister(
2826 netfnIntcOEMGeneral,
2827 static_cast<ipmi_cmd_t>(
2828 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
2829 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05302830
2831 ipmi::registerHandler(
2832 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2833 static_cast<ipmi::Cmd>(
2834 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
2835 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
2836
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05302837 ipmi::registerHandler(
2838 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2839 static_cast<ipmi::Cmd>(
2840 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
2841 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
2842
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002843 // <Get Processor Error Config>
2844 ipmi::registerHandler(
2845 ipmi::prioOemBase, netfnIntcOEMGeneral,
2846 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07002847 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002848 ipmi::Privilege::User, ipmiOEMGetProcessorErrConfig);
2849 // <Set Processor Error Config>
2850 ipmi::registerHandler(
2851 ipmi::prioOemBase, netfnIntcOEMGeneral,
2852 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07002853 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002854 ipmi::Privilege::Admin, ipmiOEMSetProcessorErrConfig);
2855
Yong Li703922d2018-11-06 13:25:31 +08002856 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2857 static_cast<ipmi_cmd_t>(
2858 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
2859 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
2860 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2861 static_cast<ipmi_cmd_t>(
2862 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
2863 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08002864
2865 ipmiPrintAndRegister(
2866 netfnIntcOEMGeneral,
2867 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
2868 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
2869
James Feist5b693632019-07-09 09:06:09 -07002870 ipmi::registerHandler(
2871 ipmi::prioOemBase, netfnIntcOEMGeneral,
2872 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
2873 ipmi::Privilege::User, ipmiOEMGetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08002874
James Feistacc8a4e2019-04-02 14:23:57 -07002875 ipmi::registerHandler(
2876 ipmi::prioOemBase, netfnIntcOEMGeneral,
2877 static_cast<ipmi::Cmd>(
2878 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
2879 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07002880
James Feistacc8a4e2019-04-02 14:23:57 -07002881 ipmi::registerHandler(
2882 ipmi::prioOemBase, netfnIntcOEMGeneral,
2883 static_cast<ipmi::Cmd>(
2884 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
2885 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
2886
2887 ipmi::registerHandler(
2888 ipmi::prioOemBase, netfnIntcOEMGeneral,
2889 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
2890 ipmi::Privilege::User, ipmiOEMSetFscParameter);
2891
2892 ipmi::registerHandler(
2893 ipmi::prioOemBase, netfnIntcOEMGeneral,
2894 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
2895 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07002896
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302897 ipmi::registerHandler(
2898 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
2899 static_cast<ipmi::Cmd>(
2900 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId),
2901 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId);
2902
Chen Yugang39736d52019-07-12 16:24:33 +08002903 ipmi::registerHandler(
2904 ipmi::prioOemBase, netfnIntcOEMGeneral,
2905 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetNmiStatus),
2906 ipmi::Privilege::User, ipmiOEMGetNmiSource);
2907
2908 ipmi::registerHandler(
2909 ipmi::prioOemBase, netfnIntcOEMGeneral,
2910 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus),
2911 ipmi::Privilege::Operator, ipmiOEMSetNmiSource);
2912
Kuiying Wang45f04982018-12-26 09:23:08 +08002913 ipmiPrintAndRegister(
2914 netfnIntcOEMGeneral,
2915 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
2916 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08002917 ipmiPrintAndRegister(
2918 netfnIntcOEMPlatform,
2919 static_cast<ipmi_cmd_t>(
2920 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
2921 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002922 ipmi::registerHandler(
2923 ipmi::prioOemBase, netfnIntcOEMGeneral,
2924 static_cast<ipmi::Cmd>(
2925 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication),
2926 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002927
Cheng C Yang773703a2019-08-15 09:41:11 +08002928 ipmi::registerHandler(
2929 ipmi::prioOemBase, netfnIntcOEMGeneral,
2930 static_cast<ipmi::Cmd>(
2931 IPMINetfnIntelOEMGeneralCmd::cmdSetColdRedundancyConfig),
2932 ipmi::Privilege::User, ipmiOEMSetCRConfig);
2933 ipmi::registerHandler(
2934 ipmi::prioOemBase, netfnIntcOEMGeneral,
2935 static_cast<ipmi::Cmd>(
2936 IPMINetfnIntelOEMGeneralCmd::cmdGetColdRedundancyConfig),
2937 ipmi::Privilege::User, ipmiOEMGetCRConfig);
2938
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002939 registerHandler(prioOemBase, netfn::intel::oemGeneral,
2940 netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
2941 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07002942
2943 ipmi::registerHandler(
2944 ipmi::prioOemBase, netfnIntcOEMGeneral,
2945 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetDimmOffset),
2946 ipmi::Privilege::Operator, ipmiOEMSetDimmOffset);
2947
2948 ipmi::registerHandler(
2949 ipmi::prioOemBase, netfnIntcOEMGeneral,
2950 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetDimmOffset),
2951 ipmi::Privilege::Operator, ipmiOEMGetDimmOffset);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002952}
2953
2954} // namespace ipmi