blob: 2d3c5c6b6067d3a1766eb36b97dbc137559831a3 [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
205ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
206 ipmi_request_t request, ipmi_response_t response,
207 ipmi_data_len_t dataLen, ipmi_context_t context)
208{
209 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
210
Jason M. Bills64796042018-10-03 16:51:55 -0700211 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800212 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800213 *dataLen = 0;
214 return IPMI_CC_REQ_DATA_LEN_INVALID;
215 }
Jason M. Bills64796042018-10-03 16:51:55 -0700216 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800217
Vernon Mauery15419dd2019-05-24 09:40:30 -0700218 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
219 std::string service = getService(*dbus, biosIntf, biosObjPath);
220 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800221 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
222 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700223 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800224 *dataLen = 1;
225 return IPMI_CC_OK;
226}
227
228ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
229 ipmi_request_t request,
230 ipmi_response_t response,
231 ipmi_data_len_t dataLen, ipmi_context_t context)
232{
233 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
234 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
235
236 if (*dataLen == 0)
237 {
Jason M. Bills64796042018-10-03 16:51:55 -0700238 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800239 return IPMI_CC_REQ_DATA_LEN_INVALID;
240 }
241
242 size_t reqDataLen = *dataLen;
243 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700244 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800245 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800246 return IPMI_CC_INVALID_FIELD_REQUEST;
247 }
248
249 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700250 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800251 {
252 case OEMDevEntityType::biosId:
253 {
254 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
255 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800256 return IPMI_CC_REQ_DATA_LEN_INVALID;
257 }
258
Vernon Mauery15419dd2019-05-24 09:40:30 -0700259 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
260 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800261 try
262 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700263 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800264 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700265 std::string& idString = std::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800266 if (req->offset >= idString.size())
267 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800268 return IPMI_CC_PARM_OUT_OF_RANGE;
269 }
Jason M. Bills64796042018-10-03 16:51:55 -0700270 size_t length = 0;
271 if (req->countToRead > (idString.size() - req->offset))
272 {
273 length = idString.size() - req->offset;
274 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800275 else
276 {
Jason M. Bills64796042018-10-03 16:51:55 -0700277 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800278 }
Jason M. Bills64796042018-10-03 16:51:55 -0700279 std::copy(idString.begin() + req->offset, idString.end(),
280 res->data);
281 res->resDatalen = length;
282 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800283 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700284 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800285 {
Jason M. Bills64796042018-10-03 16:51:55 -0700286 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800287 return IPMI_CC_UNSPECIFIED_ERROR;
288 }
289 }
290 break;
291
292 case OEMDevEntityType::devVer:
293 case OEMDevEntityType::sdrVer:
294 // TODO:
295 return IPMI_CC_ILLEGAL_COMMAND;
296 default:
297 return IPMI_CC_INVALID_FIELD_REQUEST;
298 }
299 return IPMI_CC_OK;
300}
301
302ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
303 ipmi_request_t request, ipmi_response_t response,
304 ipmi_data_len_t dataLen, ipmi_context_t context)
305{
306 if (*dataLen != 0)
307 {
Jason M. Bills64796042018-10-03 16:51:55 -0700308 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800309 return IPMI_CC_REQ_DATA_LEN_INVALID;
310 }
311
312 *dataLen = 1;
313 uint8_t* res = reinterpret_cast<uint8_t*>(response);
314 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
315 // AIC is available so that BIOS will not timeout repeatly which leads to
316 // slow booting.
317 *res = 0; // Byte1=Count of SlotPosition/FruID records.
318 return IPMI_CC_OK;
319}
320
Jason M. Bills64796042018-10-03 16:51:55 -0700321ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
322 ipmi_request_t request,
323 ipmi_response_t response,
324 ipmi_data_len_t dataLen,
325 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800326{
Jason M. Bills64796042018-10-03 16:51:55 -0700327 GetPowerRestoreDelayRes* resp =
328 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
329
330 if (*dataLen != 0)
331 {
332 *dataLen = 0;
333 return IPMI_CC_REQ_DATA_LEN_INVALID;
334 }
335
Vernon Mauery15419dd2019-05-24 09:40:30 -0700336 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700337 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700338 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700339 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700340 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700341 powerRestoreDelayIntf, powerRestoreDelayProp);
342
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700343 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700344 resp->byteLSB = delay;
345 resp->byteMSB = delay >> 8;
346
347 *dataLen = sizeof(GetPowerRestoreDelayRes);
348
349 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800350}
351
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800352static uint8_t bcdToDec(uint8_t val)
353{
354 return ((val / 16 * 10) + (val % 16));
355}
356
357// Allows an update utility or system BIOS to send the status of an embedded
358// firmware update attempt to the BMC. After received, BMC will create a logging
359// record.
360ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
361 uint8_t majorRevision,
362 uint8_t minorRevision,
363 uint32_t auxInfo)
364{
365 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700366 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800367 target = (target & selEvtTargetMask) >> selEvtTargetShift;
368
369 /* make sure the status is 0, 1, or 2 as per the spec */
370 if (status > 2)
371 {
372 return ipmi::response(ipmi::ccInvalidFieldRequest);
373 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700374 /* make sure the target is 0, 1, 2, or 4 as per the spec */
375 if (target > 4 || target == 3)
376 {
377 return ipmi::response(ipmi::ccInvalidFieldRequest);
378 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800379 /*orignal OEM command is to record OEM SEL.
380 But openbmc does not support OEM SEL, so we redirect it to redfish event
381 logging. */
382 std::string buildInfo;
383 std::string action;
384 switch (FWUpdateTarget(target))
385 {
386 case FWUpdateTarget::targetBMC:
387 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700388 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800389 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
390 " BuildID: " + std::to_string(auxInfo);
391 buildInfo += std::to_string(auxInfo);
392 break;
393 case FWUpdateTarget::targetBIOS:
394 firmware = "BIOS";
395 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700396 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800397 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
398 " minor: " +
399 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
400 " ReleaseNumber: " + // ASCII encoded
401 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
402 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
403 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
404 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
405 break;
406 case FWUpdateTarget::targetME:
407 firmware = "ME";
408 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700409 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800410 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
411 " minor2: " +
412 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
413 " build1: " +
414 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
415 " build2: " +
416 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
417 break;
418 case FWUpdateTarget::targetOEMEWS:
419 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700420 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800421 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
422 " BuildID: " + std::to_string(auxInfo);
423 break;
424 }
425
Jason M. Billsdc249272019-04-03 09:58:40 -0700426 static const std::string openBMCMessageRegistryVersion("0.1");
427 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
428
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800429 switch (status)
430 {
431 case 0x0:
432 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700433 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800434 break;
435 case 0x1:
436 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700437 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800438 break;
439 case 0x2:
440 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700441 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800442 break;
443 default:
444 action = "unknown";
445 break;
446 }
447
Jason M. Billsdc249272019-04-03 09:58:40 -0700448 std::string firmwareInstanceStr =
449 firmware + " instance: " + std::to_string(instance);
450 std::string message("[firmware update] " + firmwareInstanceStr +
451 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800452
453 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700454 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
455 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
456 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800457 return ipmi::responseSuccess();
458}
459
Jason M. Bills64796042018-10-03 16:51:55 -0700460ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
461 ipmi_request_t request,
462 ipmi_response_t response,
463 ipmi_data_len_t dataLen,
464 ipmi_context_t context)
465{
466 SetPowerRestoreDelayReq* data =
467 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
468 uint16_t delay = 0;
469
470 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
471 {
472 *dataLen = 0;
473 return IPMI_CC_REQ_DATA_LEN_INVALID;
474 }
475 delay = data->byteMSB;
476 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700477 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700478 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700479 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
480 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700481 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
482 *dataLen = 0;
483
484 return IPMI_CC_OK;
485}
486
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700487static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700488{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700489 static constexpr const char* cpuPresencePathPrefix =
490 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
491 static constexpr const char* cpuPresenceIntf =
492 "xyz.openbmc_project.Inventory.Item";
493 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
494 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
495 try
Jason M. Bills64796042018-10-03 16:51:55 -0700496 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700497 auto service =
498 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
499
500 ipmi::Value result = ipmi::getDbusProperty(
501 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
502 return std::get<bool>(result);
503 }
504 catch (const std::exception& e)
505 {
506 phosphor::logging::log<phosphor::logging::level::INFO>(
507 "Cannot find processor presence",
508 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
509 return false;
510 }
511}
512
513ipmi::RspType<bool, // CATERR Reset Enabled
514 bool, // ERR2 Reset Enabled
515 uint6_t, // reserved
516 uint8_t, // reserved, returns 0x3F
517 uint6_t, // CPU1 CATERR Count
518 uint2_t, // CPU1 Status
519 uint6_t, // CPU2 CATERR Count
520 uint2_t, // CPU2 Status
521 uint6_t, // CPU3 CATERR Count
522 uint2_t, // CPU3 Status
523 uint6_t, // CPU4 CATERR Count
524 uint2_t, // CPU4 Status
525 uint8_t // Crashdump Count
526 >
527 ipmiOEMGetProcessorErrConfig()
528{
529 bool resetOnCATERR = false;
530 bool resetOnERR2 = false;
531 uint6_t cpu1CATERRCount = 0;
532 uint6_t cpu2CATERRCount = 0;
533 uint6_t cpu3CATERRCount = 0;
534 uint6_t cpu4CATERRCount = 0;
535 uint8_t crashdumpCount = 0;
536 uint2_t cpu1Status =
537 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
538 uint2_t cpu2Status =
539 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
540 uint2_t cpu3Status =
541 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
542 uint2_t cpu4Status =
543 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
544
545 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
546 try
547 {
548 auto service = ipmi::getService(*busp, processorErrConfigIntf,
549 processorErrConfigObjPath);
550
551 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
552 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
553 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
554 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
555 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
556 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
557 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
558 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
559 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
560 }
561 catch (const std::exception& e)
562 {
563 phosphor::logging::log<phosphor::logging::level::ERR>(
564 "Failed to fetch processor error config",
565 phosphor::logging::entry("ERROR=%s", e.what()));
566 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700567 }
568
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700569 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
570 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
571 cpu2Status, cpu3CATERRCount, cpu3Status,
572 cpu4CATERRCount, cpu4Status, crashdumpCount);
573}
Jason M. Bills64796042018-10-03 16:51:55 -0700574
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700575ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
576 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
577 std::optional<bool> clearCPUErrorCount,
578 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
579{
580 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700581
582 try
583 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700584 auto service = ipmi::getService(*busp, processorErrConfigIntf,
585 processorErrConfigObjPath);
586 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
587 processorErrConfigIntf, "ResetOnCATERR",
588 resetOnCATERR);
589 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
590 processorErrConfigIntf, "ResetOnERR2",
591 resetOnERR2);
592 if (clearCPUErrorCount.value_or(false))
593 {
594 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
595 processorErrConfigIntf, "ErrorCountCPU1", 0);
596 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
597 processorErrConfigIntf, "ErrorCountCPU2", 0);
598 }
599 if (clearCrashdumpCount.value_or(false))
600 {
601 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
602 processorErrConfigIntf, "CrashdumpCount", 0);
603 }
Jason M. Bills64796042018-10-03 16:51:55 -0700604 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700605 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700606 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800607 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700608 "Failed to set processor error config",
609 phosphor::logging::entry("EXCEPTION=%s", e.what()));
610 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700611 }
612
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700613 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700614}
615
Yong Li703922d2018-11-06 13:25:31 +0800616ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
617 ipmi_request_t request,
618 ipmi_response_t response,
619 ipmi_data_len_t dataLen,
620 ipmi_context_t context)
621{
622 GetOEMShutdownPolicyRes* resp =
623 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
624
625 if (*dataLen != 0)
626 {
627 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800628 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800629 *dataLen = 0;
630 return IPMI_CC_REQ_DATA_LEN_INVALID;
631 }
632
633 *dataLen = 0;
634
635 try
636 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700637 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800638 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700639 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
640 Value variant = getDbusProperty(
641 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
642 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800643
644 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
645 convertPolicyFromString(std::get<std::string>(variant)) ==
646 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
647 NoShutdownOnOCOT)
648 {
649 resp->policy = 0;
650 }
651 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
652 convertPolicyFromString(std::get<std::string>(variant)) ==
653 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
654 Policy::ShutdownOnOCOT)
655 {
656 resp->policy = 1;
657 }
658 else
659 {
660 phosphor::logging::log<phosphor::logging::level::ERR>(
661 "oem_set_shutdown_policy: invalid property!",
662 phosphor::logging::entry(
663 "PROP=%s", std::get<std::string>(variant).c_str()));
664 return IPMI_CC_UNSPECIFIED_ERROR;
665 }
Yong Li703922d2018-11-06 13:25:31 +0800666 // TODO needs to check if it is multi-node products,
667 // policy is only supported on node 3/4
668 resp->policySupport = shutdownPolicySupported;
669 }
670 catch (sdbusplus::exception_t& e)
671 {
672 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
673 return IPMI_CC_UNSPECIFIED_ERROR;
674 }
675
676 *dataLen = sizeof(GetOEMShutdownPolicyRes);
677 return IPMI_CC_OK;
678}
679
680ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
681 ipmi_request_t request,
682 ipmi_response_t response,
683 ipmi_data_len_t dataLen,
684 ipmi_context_t context)
685{
686 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800687 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
688 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
689 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800690
691 // TODO needs to check if it is multi-node products,
692 // policy is only supported on node 3/4
693 if (*dataLen != 1)
694 {
695 phosphor::logging::log<phosphor::logging::level::ERR>(
696 "oem_set_shutdown_policy: invalid input len!");
697 *dataLen = 0;
698 return IPMI_CC_REQ_DATA_LEN_INVALID;
699 }
700
701 *dataLen = 0;
702 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
703 {
704 phosphor::logging::log<phosphor::logging::level::ERR>(
705 "oem_set_shutdown_policy: invalid input!");
706 return IPMI_CC_INVALID_FIELD_REQUEST;
707 }
708
Yong Li0669d192019-05-06 14:01:46 +0800709 if (*req == noShutdownOnOCOT)
710 {
711 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
712 Policy::NoShutdownOnOCOT;
713 }
714 else
715 {
716 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
717 Policy::ShutdownOnOCOT;
718 }
719
Yong Li703922d2018-11-06 13:25:31 +0800720 try
721 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700722 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800723 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700724 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800725 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700726 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800727 oemShutdownPolicyObjPathProp,
728 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800729 }
730 catch (sdbusplus::exception_t& e)
731 {
732 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
733 return IPMI_CC_UNSPECIFIED_ERROR;
734 }
735
736 return IPMI_CC_OK;
737}
738
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530739/** @brief implementation for check the DHCP or not in IPv4
740 * @param[in] Channel - Channel number
741 * @returns true or false.
742 */
743static bool isDHCPEnabled(uint8_t Channel)
744{
745 try
746 {
747 auto ethdevice = getChannelName(Channel);
748 if (ethdevice.empty())
749 {
750 return false;
751 }
752 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700753 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530754 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700755 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
756 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530757 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700758 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530759 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
760 {
761 return true;
762 }
763 else
764 {
765 return false;
766 }
767 }
768 catch (sdbusplus::exception_t& e)
769 {
770 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
771 return true;
772 }
773}
774
775/** @brief implementes for check the DHCP or not in IPv6
776 * @param[in] Channel - Channel number
777 * @returns true or false.
778 */
779static bool isDHCPIPv6Enabled(uint8_t Channel)
780{
781
782 try
783 {
784 auto ethdevice = getChannelName(Channel);
785 if (ethdevice.empty())
786 {
787 return false;
788 }
789 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700790 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530791 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700792 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
793 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530794 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700795 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530796 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
797 {
798 return true;
799 }
800 else
801 {
802 return false;
803 }
804 }
805 catch (sdbusplus::exception_t& e)
806 {
807 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
808 return true;
809 }
810}
811
812/** @brief implementes the creating of default new user
813 * @param[in] userName - new username in 16 bytes.
814 * @param[in] userPassword - new password in 20 bytes
815 * @returns ipmi completion code.
816 */
817ipmi::RspType<> ipmiOEMSetUser2Activation(
818 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
819 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
820{
821 bool userState = false;
822 // Check for System Interface not exist and LAN should be static
823 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
824 {
825 ChannelInfo chInfo;
826 try
827 {
828 getChannelInfo(channel, chInfo);
829 }
830 catch (sdbusplus::exception_t& e)
831 {
832 phosphor::logging::log<phosphor::logging::level::ERR>(
833 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
834 phosphor::logging::entry("MSG: %s", e.description()));
835 return ipmi::response(ipmi::ccUnspecifiedError);
836 }
837 if (chInfo.mediumType ==
838 static_cast<uint8_t>(EChannelMediumType::systemInterface))
839 {
840 phosphor::logging::log<phosphor::logging::level::ERR>(
841 "ipmiOEMSetUser2Activation: system interface exist .");
842 return ipmi::response(ipmi::ccCommandNotAvailable);
843 }
844 else
845 {
846
847 if (chInfo.mediumType ==
848 static_cast<uint8_t>(EChannelMediumType::lan8032))
849 {
850 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
851 {
852 phosphor::logging::log<phosphor::logging::level::ERR>(
853 "ipmiOEMSetUser2Activation: DHCP enabled .");
854 return ipmi::response(ipmi::ccCommandNotAvailable);
855 }
856 }
857 }
858 }
859 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
860 if (ipmi::ccSuccess ==
861 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
862 {
863 if (enabledUsers > 1)
864 {
865 phosphor::logging::log<phosphor::logging::level::ERR>(
866 "ipmiOEMSetUser2Activation: more than one user is enabled.");
867 return ipmi::response(ipmi::ccCommandNotAvailable);
868 }
869 // Check the user 2 is enabled or not
870 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
871 if (userState == true)
872 {
873 phosphor::logging::log<phosphor::logging::level::ERR>(
874 "ipmiOEMSetUser2Activation: user 2 already enabled .");
875 return ipmi::response(ipmi::ccCommandNotAvailable);
876 }
877 }
878 else
879 {
880 return ipmi::response(ipmi::ccUnspecifiedError);
881 }
882
883#if BYTE_ORDER == LITTLE_ENDIAN
884 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
885#endif
886#if BYTE_ORDER == BIG_ENDIAN
887 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
888#endif
889
890 if (ipmi::ccSuccess ==
891 ipmiUserSetUserName(ipmiDefaultUserId,
892 reinterpret_cast<const char*>(userName.data())))
893 {
894 if (ipmi::ccSuccess ==
895 ipmiUserSetUserPassword(
896 ipmiDefaultUserId,
897 reinterpret_cast<const char*>(userPassword.data())))
898 {
899 if (ipmi::ccSuccess ==
900 ipmiUserSetPrivilegeAccess(
901 ipmiDefaultUserId,
902 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
903 privAccess, true))
904 {
905 phosphor::logging::log<phosphor::logging::level::INFO>(
906 "ipmiOEMSetUser2Activation: user created successfully ");
907 return ipmi::responseSuccess();
908 }
909 }
910 // we need to delete the default user id which added in this command as
911 // password / priv setting is failed.
912 ipmiUserSetUserName(ipmiDefaultUserId, "");
913 phosphor::logging::log<phosphor::logging::level::ERR>(
914 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
915 }
916 else
917 {
918 phosphor::logging::log<phosphor::logging::level::ERR>(
919 "ipmiOEMSetUser2Activation: Setting username failed.");
920 }
921
922 return ipmi::response(ipmi::ccCommandNotAvailable);
923}
924
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +0530925/** @brief implementes setting password for special user
926 * @param[in] specialUserIndex
927 * @param[in] userPassword - new password in 20 bytes
928 * @returns ipmi completion code.
929 */
930ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
931 uint8_t specialUserIndex,
932 std::vector<uint8_t> userPassword)
933{
934 ChannelInfo chInfo;
935 try
936 {
937 getChannelInfo(ctx->channel, chInfo);
938 }
939 catch (sdbusplus::exception_t& e)
940 {
941 phosphor::logging::log<phosphor::logging::level::ERR>(
942 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
943 phosphor::logging::entry("MSG: %s", e.description()));
944 return ipmi::responseUnspecifiedError();
945 }
946 if (chInfo.mediumType !=
947 static_cast<uint8_t>(EChannelMediumType::systemInterface))
948 {
949 phosphor::logging::log<phosphor::logging::level::ERR>(
950 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
951 "interface");
952 return ipmi::responseCommandNotAvailable();
953 }
954 if (specialUserIndex != 0)
955 {
956 phosphor::logging::log<phosphor::logging::level::ERR>(
957 "ipmiOEMSetSpecialUserPassword: Invalid user account");
958 return ipmi::responseParmOutOfRange();
959 }
960 constexpr uint8_t minPasswordSizeRequired = 6;
961 if (userPassword.size() < minPasswordSizeRequired ||
962 userPassword.size() > ipmi::maxIpmi20PasswordSize)
963 {
964 return ipmi::responseReqDataLenInvalid();
965 }
966 std::string passwd;
967 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
968 userPassword.size());
969 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
970}
971
Kuiying Wang45f04982018-12-26 09:23:08 +0800972namespace ledAction
973{
974using namespace sdbusplus::xyz::openbmc_project::Led::server;
975std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
976 {Physical::Action::Off, 0x00},
977 {Physical::Action::On, 0x10},
978 {Physical::Action::Blink, 0x01}};
979
980std::map<uint8_t, std::string> offsetObjPath = {
981 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
982
983} // namespace ledAction
984
985int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
986 const std::string& objPath, uint8_t& state)
987{
988 try
989 {
990 std::string service = getService(bus, intf, objPath);
991 Value stateValue =
992 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700993 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +0800994 state = ledAction::actionDbusToIpmi.at(
995 sdbusplus::xyz::openbmc_project::Led::server::Physical::
996 convertActionFromString(strState));
997 }
998 catch (sdbusplus::exception::SdBusError& e)
999 {
1000 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1001 return -1;
1002 }
1003 return 0;
1004}
1005
1006ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1007 ipmi_request_t request, ipmi_response_t response,
1008 ipmi_data_len_t dataLen, ipmi_context_t context)
1009{
1010 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1011 // LED Status
1012 //[1:0] = Reserved
1013 //[3:2] = Status(Amber)
1014 //[5:4] = Status(Green)
1015 //[7:6] = System Identify
1016 // Status definitions:
1017 // 00b = Off
1018 // 01b = Blink
1019 // 10b = On
1020 // 11b = invalid
1021 if (*dataLen != 0)
1022 {
1023 phosphor::logging::log<phosphor::logging::level::ERR>(
1024 "oem_get_led_status: invalid input len!");
1025 *dataLen = 0;
1026 return IPMI_CC_REQ_DATA_LEN_INVALID;
1027 }
1028
1029 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1030 *resp = 0;
1031 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001032 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001033 for (auto it = ledAction::offsetObjPath.begin();
1034 it != ledAction::offsetObjPath.end(); ++it)
1035 {
1036 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001037 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001038 {
1039 phosphor::logging::log<phosphor::logging::level::ERR>(
1040 "oem_get_led_status: fail to get ID LED status!");
1041 return IPMI_CC_UNSPECIFIED_ERROR;
1042 }
1043 *resp |= state << it->first;
1044 }
1045
1046 *dataLen = sizeof(*resp);
1047 return IPMI_CC_OK;
1048}
1049
Yong Li23737fe2019-02-19 08:49:55 +08001050ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1051 ipmi_request_t request,
1052 ipmi_response_t response,
1053 ipmi_data_len_t dataLen,
1054 ipmi_context_t context)
1055{
1056 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1057 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1058
1059 if (*dataLen == 0)
1060 {
1061 phosphor::logging::log<phosphor::logging::level::ERR>(
1062 "CfgHostSerial: invalid input len!",
1063 phosphor::logging::entry("LEN=%d", *dataLen));
1064 return IPMI_CC_REQ_DATA_LEN_INVALID;
1065 }
1066
1067 switch (req->command)
1068 {
1069 case getHostSerialCfgCmd:
1070 {
1071 if (*dataLen != 1)
1072 {
1073 phosphor::logging::log<phosphor::logging::level::ERR>(
1074 "CfgHostSerial: invalid input len!");
1075 *dataLen = 0;
1076 return IPMI_CC_REQ_DATA_LEN_INVALID;
1077 }
1078
1079 *dataLen = 0;
1080
1081 boost::process::ipstream is;
1082 std::vector<std::string> data;
1083 std::string line;
1084 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1085 boost::process::std_out > is);
1086
1087 while (c1.running() && std::getline(is, line) && !line.empty())
1088 {
1089 data.push_back(line);
1090 }
1091
1092 c1.wait();
1093 if (c1.exit_code())
1094 {
1095 phosphor::logging::log<phosphor::logging::level::ERR>(
1096 "CfgHostSerial:: error on execute",
1097 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1098 // Using the default value
1099 *resp = 0;
1100 }
1101 else
1102 {
1103 if (data.size() != 1)
1104 {
1105 phosphor::logging::log<phosphor::logging::level::ERR>(
1106 "CfgHostSerial:: error on read env");
1107 return IPMI_CC_UNSPECIFIED_ERROR;
1108 }
1109 try
1110 {
1111 unsigned long tmp = std::stoul(data[0]);
1112 if (tmp > std::numeric_limits<uint8_t>::max())
1113 {
1114 throw std::out_of_range("Out of range");
1115 }
1116 *resp = static_cast<uint8_t>(tmp);
1117 }
1118 catch (const std::invalid_argument& e)
1119 {
1120 phosphor::logging::log<phosphor::logging::level::ERR>(
1121 "invalid config ",
1122 phosphor::logging::entry("ERR=%s", e.what()));
1123 return IPMI_CC_UNSPECIFIED_ERROR;
1124 }
1125 catch (const std::out_of_range& e)
1126 {
1127 phosphor::logging::log<phosphor::logging::level::ERR>(
1128 "out_of_range config ",
1129 phosphor::logging::entry("ERR=%s", e.what()));
1130 return IPMI_CC_UNSPECIFIED_ERROR;
1131 }
1132 }
1133
1134 *dataLen = 1;
1135 break;
1136 }
1137 case setHostSerialCfgCmd:
1138 {
1139 if (*dataLen != sizeof(CfgHostSerialReq))
1140 {
1141 phosphor::logging::log<phosphor::logging::level::ERR>(
1142 "CfgHostSerial: invalid input len!");
1143 *dataLen = 0;
1144 return IPMI_CC_REQ_DATA_LEN_INVALID;
1145 }
1146
1147 *dataLen = 0;
1148
1149 if (req->parameter > HostSerialCfgParamMax)
1150 {
1151 phosphor::logging::log<phosphor::logging::level::ERR>(
1152 "CfgHostSerial: invalid input!");
1153 return IPMI_CC_INVALID_FIELD_REQUEST;
1154 }
1155
1156 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1157 std::to_string(req->parameter));
1158
1159 c1.wait();
1160 if (c1.exit_code())
1161 {
1162 phosphor::logging::log<phosphor::logging::level::ERR>(
1163 "CfgHostSerial:: error on execute",
1164 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1165 return IPMI_CC_UNSPECIFIED_ERROR;
1166 }
1167 break;
1168 }
1169 default:
1170 phosphor::logging::log<phosphor::logging::level::ERR>(
1171 "CfgHostSerial: invalid input!");
1172 *dataLen = 0;
1173 return IPMI_CC_INVALID_FIELD_REQUEST;
1174 }
1175
1176 return IPMI_CC_OK;
1177}
1178
James Feist91244a62019-02-19 15:04:54 -08001179constexpr const char* thermalModeInterface =
1180 "xyz.openbmc_project.Control.ThermalMode";
1181constexpr const char* thermalModePath =
1182 "/xyz/openbmc_project/control/thermal_mode";
1183
1184bool getFanProfileInterface(
1185 sdbusplus::bus::bus& bus,
1186 boost::container::flat_map<
1187 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1188{
1189 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1190 "GetAll");
1191 call.append(thermalModeInterface);
1192 try
1193 {
1194 auto data = bus.call(call);
1195 data.read(resp);
1196 }
1197 catch (sdbusplus::exception_t& e)
1198 {
1199 phosphor::logging::log<phosphor::logging::level::ERR>(
1200 "getFanProfileInterface: can't get thermal mode!",
1201 phosphor::logging::entry("ERR=%s", e.what()));
1202 return false;
1203 }
1204 return true;
1205}
1206
1207ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1208 ipmi_request_t request, ipmi_response_t response,
1209 ipmi_data_len_t dataLen, ipmi_context_t context)
1210{
1211
1212 if (*dataLen < 2 || *dataLen > 7)
1213 {
1214 phosphor::logging::log<phosphor::logging::level::ERR>(
1215 "ipmiOEMSetFanConfig: invalid input len!");
1216 *dataLen = 0;
1217 return IPMI_CC_REQ_DATA_LEN_INVALID;
1218 }
1219
1220 // todo: tell bios to only send first 2 bytes
1221
1222 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1223 boost::container::flat_map<
1224 std::string, std::variant<std::vector<std::string>, std::string>>
1225 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001226 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1227 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001228 {
1229 return IPMI_CC_UNSPECIFIED_ERROR;
1230 }
1231
1232 std::vector<std::string>* supported =
1233 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1234 if (supported == nullptr)
1235 {
1236 return IPMI_CC_INVALID_FIELD_REQUEST;
1237 }
1238 std::string mode;
1239 if (req->flags &
1240 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1241 {
1242 bool performanceMode =
1243 (req->flags & (1 << static_cast<uint8_t>(
1244 setFanProfileFlags::performAcousSelect))) > 0;
1245
1246 if (performanceMode)
1247 {
1248
1249 if (std::find(supported->begin(), supported->end(),
1250 "Performance") != supported->end())
1251 {
1252 mode = "Performance";
1253 }
1254 }
1255 else
1256 {
1257
1258 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1259 supported->end())
1260 {
1261 mode = "Acoustic";
1262 }
1263 }
1264 if (mode.empty())
1265 {
1266 return IPMI_CC_INVALID_FIELD_REQUEST;
1267 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001268 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001269 thermalModeInterface, "Current", mode);
1270 }
1271
1272 return IPMI_CC_OK;
1273}
1274
James Feist5b693632019-07-09 09:06:09 -07001275ipmi::RspType<uint8_t, // profile support map
1276 uint8_t, // fan control profile enable
1277 uint8_t, // flags
1278 uint32_t // dimm presence bit map
1279 >
1280 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001281{
James Feist91244a62019-02-19 15:04:54 -08001282 boost::container::flat_map<
1283 std::string, std::variant<std::vector<std::string>, std::string>>
1284 profileData;
1285
Vernon Mauery15419dd2019-05-24 09:40:30 -07001286 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1287 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001288 {
James Feist5b693632019-07-09 09:06:09 -07001289 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001290 }
1291
1292 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1293
1294 if (current == nullptr)
1295 {
1296 phosphor::logging::log<phosphor::logging::level::ERR>(
1297 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001298 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001299 }
1300 bool performance = (*current == "Performance");
1301
James Feist5b693632019-07-09 09:06:09 -07001302 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001303 if (performance)
1304 {
James Feist5b693632019-07-09 09:06:09 -07001305 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001306 }
1307
James Feist5b693632019-07-09 09:06:09 -07001308 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001309}
James Feist5f957ca2019-03-14 15:33:55 -07001310constexpr const char* cfmLimitSettingPath =
1311 "/xyz/openbmc_project/control/cfm_limit";
1312constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001313constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feist09f6b602019-08-08 11:30:03 -07001314constexpr const size_t legacyPCHSensorNumber = 0x22;
1315constexpr const char* exitAirPathName = "Exit_Air";
1316constexpr const char* pchPathName = "SSB_Temp";
James Feistacc8a4e2019-04-02 14:23:57 -07001317constexpr const char* pidConfigurationIface =
1318 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001319
James Feist09f6b602019-08-08 11:30:03 -07001320static std::string getConfigPath(const std::string& name)
James Feistfaa4f222019-03-21 16:21:55 -07001321{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001322 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001323 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001324 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1325 "/xyz/openbmc_project/object_mapper",
1326 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001327
James Feistacc8a4e2019-04-02 14:23:57 -07001328 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001329 std::string path;
1330 GetSubTreeType resp;
1331 try
1332 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001333 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001334 reply.read(resp);
1335 }
1336 catch (sdbusplus::exception_t&)
1337 {
1338 phosphor::logging::log<phosphor::logging::level::ERR>(
1339 "ipmiOEMGetFscParameter: mapper error");
1340 };
James Feist09f6b602019-08-08 11:30:03 -07001341 auto config =
1342 std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) {
1343 return pair.first.find(name) != std::string::npos;
1344 });
James Feistfaa4f222019-03-21 16:21:55 -07001345 if (config != resp.end())
1346 {
1347 path = std::move(config->first);
1348 }
1349 return path;
1350}
James Feist5f957ca2019-03-14 15:33:55 -07001351
James Feistacc8a4e2019-04-02 14:23:57 -07001352// flat map to make alphabetical
1353static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1354{
1355 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001356 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001357 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001358 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1359 "/xyz/openbmc_project/object_mapper",
1360 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001361
1362 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1363 GetSubTreeType resp;
1364
1365 try
1366 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001367 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001368 reply.read(resp);
1369 }
1370 catch (sdbusplus::exception_t&)
1371 {
1372 phosphor::logging::log<phosphor::logging::level::ERR>(
1373 "getFanConfigPaths: mapper error");
1374 };
1375 for (const auto& [path, objects] : resp)
1376 {
1377 if (objects.empty())
1378 {
1379 continue; // should be impossible
1380 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001381
1382 try
1383 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001384 ret.emplace(path,
1385 getAllDbusProperties(*dbus, objects[0].first, path,
1386 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001387 }
1388 catch (sdbusplus::exception_t& e)
1389 {
1390 phosphor::logging::log<phosphor::logging::level::ERR>(
1391 "getPidConfigs: can't get DbusProperties!",
1392 phosphor::logging::entry("ERR=%s", e.what()));
1393 }
James Feistacc8a4e2019-04-02 14:23:57 -07001394 }
1395 return ret;
1396}
1397
1398ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1399{
1400 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1401 if (data.empty())
1402 {
1403 return ipmi::responseResponseError();
1404 }
1405 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1406 for (const auto& [_, pid] : data)
1407 {
1408 auto findClass = pid.find("Class");
1409 if (findClass == pid.end())
1410 {
1411 phosphor::logging::log<phosphor::logging::level::ERR>(
1412 "ipmiOEMGetFscParameter: found illegal pid "
1413 "configurations");
1414 return ipmi::responseResponseError();
1415 }
1416 std::string type = std::get<std::string>(findClass->second);
1417 if (type == "fan")
1418 {
1419 auto findOutLimit = pid.find("OutLimitMin");
1420 if (findOutLimit == pid.end())
1421 {
1422 phosphor::logging::log<phosphor::logging::level::ERR>(
1423 "ipmiOEMGetFscParameter: found illegal pid "
1424 "configurations");
1425 return ipmi::responseResponseError();
1426 }
1427 // get the min out of all the offsets
1428 minOffset = std::min(
1429 minOffset,
1430 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1431 }
1432 }
1433 if (minOffset == std::numeric_limits<uint8_t>::max())
1434 {
1435 phosphor::logging::log<phosphor::logging::level::ERR>(
1436 "ipmiOEMGetFscParameter: found no fan configurations!");
1437 return ipmi::responseResponseError();
1438 }
1439
1440 return ipmi::responseSuccess(minOffset);
1441}
1442
1443ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1444{
1445 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1446 if (data.empty())
1447 {
1448
1449 phosphor::logging::log<phosphor::logging::level::ERR>(
1450 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1451 return ipmi::responseResponseError();
1452 }
1453
Vernon Mauery15419dd2019-05-24 09:40:30 -07001454 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001455 bool found = false;
1456 for (const auto& [path, pid] : data)
1457 {
1458 auto findClass = pid.find("Class");
1459 if (findClass == pid.end())
1460 {
1461
1462 phosphor::logging::log<phosphor::logging::level::ERR>(
1463 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1464 "configurations");
1465 return ipmi::responseResponseError();
1466 }
1467 std::string type = std::get<std::string>(findClass->second);
1468 if (type == "fan")
1469 {
1470 auto findOutLimit = pid.find("OutLimitMin");
1471 if (findOutLimit == pid.end())
1472 {
1473
1474 phosphor::logging::log<phosphor::logging::level::ERR>(
1475 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1476 "configurations");
1477 return ipmi::responseResponseError();
1478 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001479 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001480 path, pidConfigurationIface, "OutLimitMin",
1481 static_cast<double>(offset));
1482 found = true;
1483 }
1484 }
1485 if (!found)
1486 {
1487 phosphor::logging::log<phosphor::logging::level::ERR>(
1488 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1489 return ipmi::responseResponseError();
1490 }
1491
1492 return ipmi::responseSuccess();
1493}
1494
1495ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1496 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001497{
1498 constexpr const size_t disableLimiting = 0x0;
1499
Vernon Mauery15419dd2019-05-24 09:40:30 -07001500 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001501 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001502 {
James Feist09f6b602019-08-08 11:30:03 -07001503 std::string pathName;
James Feistacc8a4e2019-04-02 14:23:57 -07001504 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001505 {
James Feist09f6b602019-08-08 11:30:03 -07001506 pathName = exitAirPathName;
1507 }
1508 else if (param1 == legacyPCHSensorNumber)
1509 {
1510 pathName = pchPathName;
James Feistfaa4f222019-03-21 16:21:55 -07001511 }
1512 else
1513 {
James Feistacc8a4e2019-04-02 14:23:57 -07001514 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001515 }
James Feist09f6b602019-08-08 11:30:03 -07001516 std::string path = getConfigPath(pathName);
1517 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path,
1518 pidConfigurationIface, "SetPoint",
1519 static_cast<double>(param2));
1520 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001521 }
James Feistacc8a4e2019-04-02 14:23:57 -07001522 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001523 {
James Feistacc8a4e2019-04-02 14:23:57 -07001524 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001525
1526 // must be greater than 50 based on eps
1527 if (cfm < 50 && cfm != disableLimiting)
1528 {
James Feistacc8a4e2019-04-02 14:23:57 -07001529 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001530 }
1531
1532 try
1533 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001534 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001535 cfmLimitIface, "Limit",
1536 static_cast<double>(cfm));
1537 }
1538 catch (sdbusplus::exception_t& e)
1539 {
1540 phosphor::logging::log<phosphor::logging::level::ERR>(
1541 "ipmiOEMSetFscParameter: can't set cfm setting!",
1542 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001543 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001544 }
James Feistacc8a4e2019-04-02 14:23:57 -07001545 return ipmi::responseSuccess();
1546 }
1547 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1548 {
1549 constexpr const size_t maxDomainCount = 8;
1550 uint8_t requestedDomainMask = param1;
1551 boost::container::flat_map data = getPidConfigs();
1552 if (data.empty())
1553 {
1554
1555 phosphor::logging::log<phosphor::logging::level::ERR>(
1556 "ipmiOEMSetFscParameter: found no pid configurations!");
1557 return ipmi::responseResponseError();
1558 }
1559 size_t count = 0;
1560 for (const auto& [path, pid] : data)
1561 {
1562 auto findClass = pid.find("Class");
1563 if (findClass == pid.end())
1564 {
1565
1566 phosphor::logging::log<phosphor::logging::level::ERR>(
1567 "ipmiOEMSetFscParameter: found illegal pid "
1568 "configurations");
1569 return ipmi::responseResponseError();
1570 }
1571 std::string type = std::get<std::string>(findClass->second);
1572 if (type == "fan")
1573 {
1574 if (requestedDomainMask & (1 << count))
1575 {
1576 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001577 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001578 pidConfigurationIface, "OutLimitMax",
1579 static_cast<double>(param2));
1580 }
1581 count++;
1582 }
1583 }
1584 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001585 }
1586 else
1587 {
1588 // todo other command parts possibly
1589 // tcontrol is handled in peci now
1590 // fan speed offset not implemented yet
1591 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001592 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001593 }
1594}
1595
James Feistacc8a4e2019-04-02 14:23:57 -07001596ipmi::RspType<
1597 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1598 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001599{
James Feist09f6b602019-08-08 11:30:03 -07001600 constexpr uint8_t legacyDefaultSetpoint = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001601
Vernon Mauery15419dd2019-05-24 09:40:30 -07001602 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001603 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001604 {
James Feistacc8a4e2019-04-02 14:23:57 -07001605 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001606 {
James Feistacc8a4e2019-04-02 14:23:57 -07001607 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001608 }
1609
James Feist09f6b602019-08-08 11:30:03 -07001610 std::string pathName;
1611
1612 if (*param == legacyExitAirSensorNumber)
1613 {
1614 pathName = exitAirPathName;
1615 }
1616 else if (*param == legacyPCHSensorNumber)
1617 {
1618 pathName = pchPathName;
1619 }
1620 else
James Feistfaa4f222019-03-21 16:21:55 -07001621 {
James Feistacc8a4e2019-04-02 14:23:57 -07001622 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001623 }
James Feist09f6b602019-08-08 11:30:03 -07001624
1625 uint8_t setpoint = legacyDefaultSetpoint;
1626 std::string path = getConfigPath(pathName);
James Feistfaa4f222019-03-21 16:21:55 -07001627 if (path.size())
1628 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001629 Value val = ipmi::getDbusProperty(
1630 *dbus, "xyz.openbmc_project.EntityManager", path,
1631 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001632 setpoint = std::floor(std::get<double>(val) + 0.5);
1633 }
1634
1635 // old implementation used to return the "default" and current, we
1636 // don't make the default readily available so just make both the
1637 // same
James Feistfaa4f222019-03-21 16:21:55 -07001638
James Feistacc8a4e2019-04-02 14:23:57 -07001639 return ipmi::responseSuccess(
1640 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001641 }
James Feistacc8a4e2019-04-02 14:23:57 -07001642 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1643 {
1644 constexpr const size_t maxDomainCount = 8;
1645
1646 if (!param)
1647 {
1648 return ipmi::responseReqDataLenInvalid();
1649 }
1650 uint8_t requestedDomain = *param;
1651 if (requestedDomain >= maxDomainCount)
1652 {
1653 return ipmi::responseInvalidFieldRequest();
1654 }
1655
1656 boost::container::flat_map data = getPidConfigs();
1657 if (data.empty())
1658 {
1659 phosphor::logging::log<phosphor::logging::level::ERR>(
1660 "ipmiOEMGetFscParameter: found no pid configurations!");
1661 return ipmi::responseResponseError();
1662 }
1663 size_t count = 0;
1664 for (const auto& [_, pid] : data)
1665 {
1666 auto findClass = pid.find("Class");
1667 if (findClass == pid.end())
1668 {
1669 phosphor::logging::log<phosphor::logging::level::ERR>(
1670 "ipmiOEMGetFscParameter: found illegal pid "
1671 "configurations");
1672 return ipmi::responseResponseError();
1673 }
1674 std::string type = std::get<std::string>(findClass->second);
1675 if (type == "fan")
1676 {
1677 if (requestedDomain == count)
1678 {
1679 auto findOutLimit = pid.find("OutLimitMax");
1680 if (findOutLimit == pid.end())
1681 {
1682 phosphor::logging::log<phosphor::logging::level::ERR>(
1683 "ipmiOEMGetFscParameter: found illegal pid "
1684 "configurations");
1685 return ipmi::responseResponseError();
1686 }
1687
1688 return ipmi::responseSuccess(
1689 static_cast<uint8_t>(std::floor(
1690 std::get<double>(findOutLimit->second) + 0.5)));
1691 }
1692 else
1693 {
1694 count++;
1695 }
1696 }
1697 }
1698
1699 return ipmi::responseInvalidFieldRequest();
1700 }
1701 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001702 {
1703
1704 /*
1705 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001706 previous behavior didn't seem to prevent this, ignore the check for
1707 now.
James Feist5f957ca2019-03-14 15:33:55 -07001708
James Feistacc8a4e2019-04-02 14:23:57 -07001709 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001710 {
1711 phosphor::logging::log<phosphor::logging::level::ERR>(
1712 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001713 return IPMI_CC_REQ_DATA_LEN_INVALID;
1714 }
1715 */
1716 Value cfmLimit;
1717 Value cfmMaximum;
1718 try
1719 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001720 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001721 cfmLimitSettingPath, cfmLimitIface,
1722 "Limit");
1723 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001724 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001725 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1726 }
1727 catch (sdbusplus::exception_t& e)
1728 {
1729 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001730 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001731 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001732 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001733 }
1734
James Feistacc8a4e2019-04-02 14:23:57 -07001735 double cfmMax = std::get<double>(cfmMaximum);
1736 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001737
James Feistacc8a4e2019-04-02 14:23:57 -07001738 cfmLim = std::floor(cfmLim + 0.5);
1739 cfmMax = std::floor(cfmMax + 0.5);
1740 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1741 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001742
James Feistacc8a4e2019-04-02 14:23:57 -07001743 return ipmi::responseSuccess(
1744 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001745 }
James Feistacc8a4e2019-04-02 14:23:57 -07001746
James Feist5f957ca2019-03-14 15:33:55 -07001747 else
1748 {
1749 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001750 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001751 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001752 }
1753}
1754
Cheng C Yang773703a2019-08-15 09:41:11 +08001755using crConfigVariant =
1756 std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>;
1757
1758int setCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1759 const crConfigVariant& value,
1760 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1761{
1762 boost::system::error_code ec;
1763 ctx->bus->yield_method_call<void>(
1764 *(ctx->yield), ec, "xyz.openbmc_project.Settings",
1765 "/xyz/openbmc_project/control/power_supply_redundancy",
1766 "org.freedesktop.DBus.Properties", "Set",
1767 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value);
1768 if (ec)
1769 {
1770 phosphor::logging::log<phosphor::logging::level::ERR>(
1771 "Failed to set dbus property to cold redundancy");
1772 return -1;
1773 }
1774
1775 return 0;
1776}
1777
1778int getCRConfig(ipmi::Context::ptr ctx, const std::string& property,
1779 crConfigVariant& value,
1780 std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT)
1781{
1782 boost::system::error_code ec;
1783 value = ctx->bus->yield_method_call<crConfigVariant>(
1784 *(ctx->yield), ec, "xyz.openbmc_project.Settings",
1785 "/xyz/openbmc_project/control/power_supply_redundancy",
1786 "org.freedesktop.DBus.Properties", "Get",
1787 "xyz.openbmc_project.Control.PowerSupplyRedundancy", property);
1788 if (ec)
1789 {
1790 phosphor::logging::log<phosphor::logging::level::ERR>(
1791 "Failed to get dbus property to cold redundancy");
1792 return -1;
1793 }
1794 return 0;
1795}
1796
1797uint8_t getPSUCount(void)
1798{
1799 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1800 ipmi::Value num;
1801 try
1802 {
1803 num = ipmi::getDbusProperty(
1804 *dbus, "xyz.openbmc_project.PSURedundancy",
1805 "/xyz/openbmc_project/control/power_supply_redundancy",
1806 "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber");
1807 }
1808 catch (sdbusplus::exception_t& e)
1809 {
1810 phosphor::logging::log<phosphor::logging::level::ERR>(
1811 "Failed to get PSUNumber property from dbus interface");
1812 return 0;
1813 }
1814 uint8_t* pNum = std::get_if<uint8_t>(&num);
1815 if (!pNum)
1816 {
1817 phosphor::logging::log<phosphor::logging::level::ERR>(
1818 "Error to get PSU Number");
1819 return 0;
1820 }
1821 return *pNum;
1822}
1823
1824bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num)
1825{
1826 if (conf.size() < num)
1827 {
1828 phosphor::logging::log<phosphor::logging::level::ERR>(
1829 "Invalid PSU Ranking");
1830 return false;
1831 }
1832 std::set<uint8_t> confSet;
1833 for (uint8_t i = 0; i < num; i++)
1834 {
1835 if (conf[i] > num)
1836 {
1837 phosphor::logging::log<phosphor::logging::level::ERR>(
1838 "PSU Ranking is larger than current PSU number");
1839 return false;
1840 }
1841 confSet.emplace(conf[i]);
1842 }
1843
1844 if (confSet.size() != num)
1845 {
1846 phosphor::logging::log<phosphor::logging::level::ERR>(
1847 "duplicate PSU Ranking");
1848 return false;
1849 }
1850 return true;
1851}
1852
1853enum class crParameter
1854{
1855 crStatus = 0,
1856 crFeature = 1,
1857 rotationFeature = 2,
1858 rotationAlgo = 3,
1859 rotationPeriod = 4,
1860 numOfPSU = 5
1861};
1862
1863constexpr ipmi::Cc ccParameterNotSupported = 0x80;
1864static const constexpr uint32_t oneDay = 0x15180;
1865static const constexpr uint32_t oneMonth = 0xf53700;
1866static const constexpr uint8_t userSpecific = 0x01;
1867static const constexpr uint8_t crSetCompleted = 0;
1868ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx,
1869 uint8_t parameter,
1870 ipmi::message::Payload& payload)
1871{
1872 switch (static_cast<crParameter>(parameter))
1873 {
1874 case crParameter::crFeature:
1875 {
1876 uint8_t param1;
1877 if (payload.unpack(param1) || !payload.fullyUnpacked())
1878 {
1879 return ipmi::responseReqDataLenInvalid();
1880 }
1881 // ColdRedundancy Enable can only be true or flase
1882 if (param1 > 1)
1883 {
1884 return ipmi::responseInvalidFieldRequest();
1885 }
1886 if (setCRConfig(ctx, "ColdRedundancyEnabled",
1887 static_cast<bool>(param1)))
1888 {
1889 return ipmi::responseResponseError();
1890 }
1891 break;
1892 }
1893 case crParameter::rotationFeature:
1894 {
1895 uint8_t param1;
1896 if (payload.unpack(param1) || !payload.fullyUnpacked())
1897 {
1898 return ipmi::responseReqDataLenInvalid();
1899 }
1900 // Rotation Enable can only be true or false
1901 if (param1 > 1)
1902 {
1903 return ipmi::responseInvalidFieldRequest();
1904 }
1905 if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1)))
1906 {
1907 return ipmi::responseResponseError();
1908 }
1909 break;
1910 }
1911 case crParameter::rotationAlgo:
1912 {
1913 // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific
1914 std::string algoName;
1915 uint8_t param1;
1916 if (payload.unpack(param1))
1917 {
1918 return ipmi::responseReqDataLenInvalid();
1919 }
1920 switch (param1)
1921 {
1922 case 0:
1923 algoName = "xyz.openbmc_project.Control."
1924 "PowerSupplyRedundancy.Algo.bmcSpecific";
1925 break;
1926 case 1:
1927 algoName = "xyz.openbmc_project.Control."
1928 "PowerSupplyRedundancy.Algo.userSpecific";
1929 break;
1930 default:
1931 return ipmi::responseInvalidFieldRequest();
1932 }
1933 if (setCRConfig(ctx, "RotationAlgorithm", algoName))
1934 {
1935 return ipmi::responseResponseError();
1936 }
1937
1938 uint8_t numberOfPSU = getPSUCount();
1939 if (!numberOfPSU)
1940 {
1941 return ipmi::responseResponseError();
1942 }
1943 std::vector<uint8_t> rankOrder;
1944
1945 if (param1 == userSpecific)
1946 {
1947 if (payload.unpack(rankOrder) || !payload.fullyUnpacked())
1948 {
1949 ipmi::responseReqDataLenInvalid();
1950 }
1951 if (rankOrder.size() < numberOfPSU)
1952 {
1953 return ipmi::responseReqDataLenInvalid();
1954 }
1955
1956 if (!validateCRAlgo(rankOrder, numberOfPSU))
1957 {
1958 return ipmi::responseInvalidFieldRequest();
1959 }
1960 }
1961 else
1962 {
1963 if (rankOrder.size() > 0)
1964 {
1965 return ipmi::responseReqDataLenInvalid();
1966 }
1967 for (uint8_t i = 1; i <= numberOfPSU; i++)
1968 {
1969 rankOrder.emplace_back(i);
1970 }
1971 }
1972 if (setCRConfig(ctx, "RotationRankOrder", rankOrder))
1973 {
1974 return ipmi::responseResponseError();
1975 }
1976 break;
1977 }
1978 case crParameter::rotationPeriod:
1979 {
1980 // Minimum Rotation period is One day (86400 seconds) and Max
1981 // Rotation Period is 6 month (0xf53700 seconds)
1982 uint32_t period;
1983 if (payload.unpack(period) || !payload.fullyUnpacked())
1984 {
1985 return ipmi::responseReqDataLenInvalid();
1986 }
1987 if ((period < oneDay) || (period > oneMonth))
1988 {
1989 return ipmi::responseInvalidFieldRequest();
1990 }
1991 if (setCRConfig(ctx, "PeriodOfRotation", period))
1992 {
1993 return ipmi::responseResponseError();
1994 }
1995 break;
1996 }
1997 default:
1998 {
1999 return ipmi::response(ccParameterNotSupported);
2000 }
2001 }
2002
2003 // TODO Halfwidth needs to set SetInProgress
2004 if (setCRConfig(ctx, "ColdRedundancyStatus",
2005 "xyz.openbmc_project.Control.PowerSupplyRedundancy.Status."
2006 "completed"))
2007 {
2008 return ipmi::responseResponseError();
2009 }
2010 return ipmi::responseSuccess(crSetCompleted);
2011}
2012
2013ipmi::RspType<std::variant<uint8_t, uint32_t, std::array<uint8_t, 5>>>
2014 ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter)
2015{
2016 crConfigVariant value;
2017 switch (static_cast<crParameter>(parameter))
2018 {
2019 case crParameter::crStatus:
2020 {
2021 if (getCRConfig(ctx, "ColdRedundancyStatus", value))
2022 {
2023 return ipmi::responseResponseError();
2024 }
2025 std::string* pStatus = std::get_if<std::string>(&value);
2026 if (!pStatus)
2027 {
2028 phosphor::logging::log<phosphor::logging::level::ERR>(
2029 "Error to get ColdRedundancyStatus property");
2030 return ipmi::responseResponseError();
2031 }
2032 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2033 auto status =
2034 server::PowerSupplyRedundancy::convertStatusFromString(
2035 *pStatus);
2036 switch (status)
2037 {
2038 case server::PowerSupplyRedundancy::Status::inProgress:
2039 return ipmi::responseSuccess(static_cast<uint8_t>(0));
2040
2041 case server::PowerSupplyRedundancy::Status::completed:
2042 return ipmi::responseSuccess(static_cast<uint8_t>(1));
2043 default:
2044 phosphor::logging::log<phosphor::logging::level::ERR>(
2045 "Error to get valid status");
2046 return ipmi::responseResponseError();
2047 }
2048 }
2049 case crParameter::crFeature:
2050 {
2051 if (getCRConfig(ctx, "ColdRedundancyEnabled", value))
2052 {
2053 return ipmi::responseResponseError();
2054 }
2055 bool* pResponse = std::get_if<bool>(&value);
2056 if (!pResponse)
2057 {
2058 phosphor::logging::log<phosphor::logging::level::ERR>(
2059 "Error to get ColdRedundancyEnable property");
2060 return ipmi::responseResponseError();
2061 }
2062
2063 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse));
2064 }
2065 case crParameter::rotationFeature:
2066 {
2067 if (getCRConfig(ctx, "RotationEnabled", value))
2068 {
2069 return ipmi::responseResponseError();
2070 }
2071 bool* pResponse = std::get_if<bool>(&value);
2072 if (!pResponse)
2073 {
2074 phosphor::logging::log<phosphor::logging::level::ERR>(
2075 "Error to get RotationEnabled property");
2076 return ipmi::responseResponseError();
2077 }
2078 return ipmi::responseSuccess(static_cast<uint8_t>(*pResponse));
2079 }
2080 case crParameter::rotationAlgo:
2081 {
2082 if (getCRConfig(ctx, "RotationAlgorithm", value))
2083 {
2084 return ipmi::responseResponseError();
2085 }
2086
2087 std::string* pAlgo = std::get_if<std::string>(&value);
2088 if (!pAlgo)
2089 {
2090 phosphor::logging::log<phosphor::logging::level::ERR>(
2091 "Error to get RotationAlgorithm property");
2092 return ipmi::responseResponseError();
2093 }
2094 std::array<uint8_t, 5> response = {0, 0, 0, 0, 0};
2095 namespace server = sdbusplus::xyz::openbmc_project::Control::server;
2096 auto algo =
2097 server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo);
2098 switch (algo)
2099 {
2100 case server::PowerSupplyRedundancy::Algo::bmcSpecific:
2101 response[0] = 0;
2102 break;
2103 case server::PowerSupplyRedundancy::Algo::userSpecific:
2104 response[0] = 1;
2105 break;
2106 default:
2107 phosphor::logging::log<phosphor::logging::level::ERR>(
2108 "Error to get valid algo");
2109 return ipmi::responseResponseError();
2110 }
2111
2112 if (getCRConfig(ctx, "RotationRankOrder", value))
2113 {
2114 return ipmi::responseResponseError();
2115 }
2116 std::vector<uint8_t>* pResponse =
2117 std::get_if<std::vector<uint8_t>>(&value);
2118 if (!pResponse)
2119 {
2120 phosphor::logging::log<phosphor::logging::level::ERR>(
2121 "Error to get RotationRankOrder property");
2122 return ipmi::responseResponseError();
2123 }
2124 if (pResponse->size() + 1 > response.size())
2125 {
2126 phosphor::logging::log<phosphor::logging::level::ERR>(
2127 "Incorrect size of RotationAlgorithm property");
2128 return ipmi::responseResponseError();
2129 }
2130 std::copy(pResponse->begin(), pResponse->end(),
2131 response.begin() + 1);
2132 return ipmi::responseSuccess(response);
2133 }
2134 case crParameter::rotationPeriod:
2135 {
2136 if (getCRConfig(ctx, "PeriodOfRotation", value))
2137 {
2138 return ipmi::responseResponseError();
2139 }
2140 uint32_t* pResponse = std::get_if<uint32_t>(&value);
2141 if (!pResponse)
2142 {
2143 phosphor::logging::log<phosphor::logging::level::ERR>(
2144 "Error to get RotationAlgorithm property");
2145 return ipmi::responseResponseError();
2146 }
2147 return ipmi::responseSuccess(*pResponse);
2148 }
2149 case crParameter::numOfPSU:
2150 {
2151 uint8_t numberOfPSU = getPSUCount();
2152 if (!numberOfPSU)
2153 {
2154 return ipmi::responseResponseError();
2155 }
2156 return ipmi::responseSuccess(numberOfPSU);
2157 }
2158 default:
2159 {
2160 return ipmi::response(ccParameterNotSupported);
2161 }
2162 }
2163}
2164
Zhu, Yungebe560b02019-04-21 21:19:21 -04002165ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
2166 uint8_t faultState,
2167 uint8_t faultGroup,
2168 std::array<uint8_t, 8>& ledStateData)
2169{
2170 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
2171 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
2172 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
2173 static const std::array<std::string, maxFaultType> faultNames = {
2174 "faultFan", "faultTemp", "faultPower",
2175 "faultDriveSlot", "faultSoftware", "faultMemory"};
2176 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
2177 static constexpr const char* postfixValue = "/value";
2178
2179 constexpr uint8_t maxFaultSource = 0x4;
2180 constexpr uint8_t skipLEDs = 0xFF;
2181 constexpr uint8_t pinSize = 64;
2182 constexpr uint8_t groupSize = 16;
2183
2184 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
2185 uint64_t resFIndex = 0;
2186 std::string resFType;
2187 std::string service;
2188 ObjectValueTree valueTree;
2189
2190 // Validate the source, fault type
2191 if ((sourceId >= maxFaultSource) ||
2192 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
2193 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
2194 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
2195 {
2196 return ipmi::responseParmOutOfRange();
2197 }
2198
Vernon Mauery15419dd2019-05-24 09:40:30 -07002199 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04002200 try
2201 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002202 service = getService(*dbus, intf, objpath);
2203 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04002204 }
2205 catch (const std::exception& e)
2206 {
2207 phosphor::logging::log<phosphor::logging::level::ERR>(
2208 "No object implements interface",
2209 phosphor::logging::entry("SERVICE=%s", service.c_str()),
2210 phosphor::logging::entry("INTF=%s", intf));
2211 return ipmi::responseResponseError();
2212 }
2213
2214 if (valueTree.empty())
2215 {
2216 phosphor::logging::log<phosphor::logging::level::ERR>(
2217 "No object implements interface",
2218 phosphor::logging::entry("INTF=%s", intf));
2219 return ipmi::responseResponseError();
2220 }
2221
2222 for (const auto& item : valueTree)
2223 {
2224 // find LedFault configuration
2225 auto interface =
2226 item.second.find("xyz.openbmc_project.Configuration.LedFault");
2227 if (interface == item.second.end())
2228 {
2229 continue;
2230 }
2231
2232 // find matched fault type: faultMemmory / faultFan
2233 // find LedGpioPins/FaultIndex configuration
2234 auto propertyFaultType = interface->second.find("FaultType");
2235 auto propertyFIndex = interface->second.find("FaultIndex");
2236 auto ledIndex = interface->second.find("LedGpioPins");
2237
2238 if (propertyFaultType == interface->second.end() ||
2239 propertyFIndex == interface->second.end() ||
2240 ledIndex == interface->second.end())
2241 {
2242 continue;
2243 }
2244
2245 try
2246 {
2247 Value valIndex = propertyFIndex->second;
2248 resFIndex = std::get<uint64_t>(valIndex);
2249
2250 Value valFType = propertyFaultType->second;
2251 resFType = std::get<std::string>(valFType);
2252 }
2253 catch (const std::bad_variant_access& e)
2254 {
2255 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2256 return ipmi::responseResponseError();
2257 }
2258 // find the matched requested fault type: faultMemmory or faultFan
2259 if (resFType != faultNames[faultType])
2260 {
2261 continue;
2262 }
2263
2264 // read LedGpioPins data
2265 std::vector<uint64_t> ledgpios;
2266 std::variant<std::vector<uint64_t>> message;
2267
Vernon Mauery15419dd2019-05-24 09:40:30 -07002268 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04002269 service.c_str(), (std::string(item.first)).c_str(),
2270 "org.freedesktop.DBus.Properties", "Get");
2271
2272 method.append("xyz.openbmc_project.Configuration.LedFault",
2273 "LedGpioPins");
2274
2275 try
2276 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002277 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002278 reply.read(message);
2279 ledgpios = std::get<std::vector<uint64_t>>(message);
2280 }
2281 catch (std::exception& e)
2282 {
2283 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2284 return ipmi::responseResponseError();
2285 }
2286
2287 // Check the size to be sure it will never overflow on groupSize
2288 if (ledgpios.size() > groupSize)
2289 {
2290 phosphor::logging::log<phosphor::logging::level::ERR>(
2291 "Fault gpio Pins out of range!");
2292 return ipmi::responseParmOutOfRange();
2293 }
2294 // Store data, according to command data bit index order
2295 for (int i = 0; i < ledgpios.size(); i++)
2296 {
2297 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
2298 }
2299 }
2300
2301 switch (RemoteFaultType(faultType))
2302 {
2303 case (RemoteFaultType::fan):
2304 case (RemoteFaultType::memory):
2305 {
2306 if (faultGroup == skipLEDs)
2307 {
2308 return ipmi::responseSuccess();
2309 }
2310
2311 uint64_t ledState = 0;
2312 // calculate led state bit filed count, each byte has 8bits
2313 // the maximum bits will be 8 * 8 bits
2314 constexpr uint8_t size = sizeof(ledStateData) * 8;
2315 for (int i = 0; i < sizeof(ledStateData); i++)
2316 {
2317 ledState = (uint64_t)(ledState << 8);
2318 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
2319 }
2320
2321 std::bitset<size> ledStateBits(ledState);
2322 std::string gpioValue;
2323 for (int i = 0; i < size; i++)
2324 { // skip invalid value
2325 if (ledFaultPins[i] == 0xFFFF)
2326 {
2327 continue;
2328 }
2329
2330 std::string device = sysGpioPath +
2331 std::to_string(ledFaultPins[i]) +
2332 postfixValue;
2333 std::fstream gpioFile;
2334
2335 gpioFile.open(device, std::ios::out);
2336
2337 if (!gpioFile.good())
2338 {
2339 phosphor::logging::log<phosphor::logging::level::ERR>(
2340 "Not Find Led Gpio Device!",
2341 phosphor::logging::entry("DEVICE=%s", device.c_str()));
2342 return ipmi::responseResponseError();
2343 }
2344 gpioFile << std::to_string(
2345 static_cast<uint8_t>(ledStateBits[i]));
2346 gpioFile.close();
2347 }
2348 break;
2349 }
2350 default:
2351 {
2352 // now only support two fault types
2353 return ipmi::responseParmOutOfRange();
2354 }
2355 }
2356
2357 return ipmi::responseSuccess();
2358}
2359
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302360ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
2361{
2362 uint8_t prodId = 0;
2363 try
2364 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07002365 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302366 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002367 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302368 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
2369 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07002370 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302371 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
2372 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
2373 }
2374 catch (std::exception& e)
2375 {
2376 phosphor::logging::log<phosphor::logging::level::ERR>(
2377 "ipmiOEMReadBoardProductId: Product ID read failed!",
2378 phosphor::logging::entry("ERR=%s", e.what()));
2379 }
2380 return ipmi::responseSuccess(prodId);
2381}
2382
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002383ipmi::RspType<uint8_t /* restore status */>
2384 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
2385{
2386 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
2387
2388 if (clr != expClr)
2389 {
2390 return ipmi::responseInvalidFieldRequest();
2391 }
2392 constexpr uint8_t cmdStatus = 0;
2393 constexpr uint8_t cmdDefaultRestore = 0xaa;
2394 constexpr uint8_t cmdFullRestore = 0xbb;
2395 constexpr uint8_t cmdFormat = 0xcc;
2396
2397 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
2398
2399 switch (cmd)
2400 {
2401 case cmdStatus:
2402 break;
2403 case cmdDefaultRestore:
2404 case cmdFullRestore:
2405 case cmdFormat:
2406 {
2407 // write file to rwfs root
2408 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
2409 std::ofstream restoreFile(restoreOpFname);
2410 if (!restoreFile)
2411 {
2412 return ipmi::responseUnspecifiedError();
2413 }
2414 restoreFile << value << "\n";
2415 break;
2416 }
2417 default:
2418 return ipmi::responseInvalidFieldRequest();
2419 }
2420
2421 constexpr uint8_t restorePending = 0;
2422 constexpr uint8_t restoreComplete = 1;
2423
2424 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
2425 ? restorePending
2426 : restoreComplete;
2427 return ipmi::responseSuccess(restoreStatus);
2428}
2429
Chen Yugang39736d52019-07-12 16:24:33 +08002430ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
2431{
2432 uint8_t bmcSource;
2433 namespace nmi = sdbusplus::com::intel::Control::server;
2434
2435 try
2436 {
2437 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2438 std::string service =
2439 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2440 Value variant =
2441 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2442 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2443
2444 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2445 std::get<std::string>(variant)))
2446 {
2447 case nmi::NMISource::BMCSourceSignal::None:
2448 bmcSource = static_cast<uint8_t>(NmiSource::none);
2449 break;
2450 case nmi::NMISource::BMCSourceSignal::FpBtn:
2451 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
2452 break;
2453 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
2454 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
2455 break;
2456 case nmi::NMISource::BMCSourceSignal::PefMatch:
2457 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
2458 break;
2459 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2460 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2461 break;
2462 case nmi::NMISource::BMCSourceSignal::MemoryError:
2463 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2464 break;
2465 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
2466 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
2467 break;
2468 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
2469 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
2470 break;
2471 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
2472 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
2473 break;
2474 default:
2475 phosphor::logging::log<phosphor::logging::level::ERR>(
2476 "NMI source: invalid property!",
2477 phosphor::logging::entry(
2478 "PROP=%s", std::get<std::string>(variant).c_str()));
2479 return ipmi::responseResponseError();
2480 }
2481 }
2482 catch (sdbusplus::exception::SdBusError& e)
2483 {
2484 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2485 return ipmi::responseResponseError();
2486 }
2487
2488 return ipmi::responseSuccess(bmcSource);
2489}
2490
2491ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2492{
2493 namespace nmi = sdbusplus::com::intel::Control::server;
2494
2495 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2496 nmi::NMISource::BMCSourceSignal::None;
2497
2498 switch (NmiSource(sourceId))
2499 {
2500 case NmiSource::none:
2501 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2502 break;
2503 case NmiSource::fpBtn:
2504 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2505 break;
2506 case NmiSource::wdPreTimeout:
2507 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2508 break;
2509 case NmiSource::pefMatch:
2510 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2511 break;
2512 case NmiSource::chassisCmd:
2513 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2514 break;
2515 case NmiSource::memoryError:
2516 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2517 break;
2518 case NmiSource::pciSerrPerr:
2519 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2520 break;
2521 case NmiSource::southbridgeNmi:
2522 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2523 break;
2524 case NmiSource::chipsetNmi:
2525 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2526 break;
2527 default:
2528 phosphor::logging::log<phosphor::logging::level::ERR>(
2529 "NMI source: invalid property!");
2530 return ipmi::responseResponseError();
2531 }
2532
2533 try
2534 {
2535 // keep NMI signal source
2536 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2537 std::string service =
2538 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2539 setDbusProperty(
2540 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2541 oemNmiBmcSourceObjPathProp,
2542 sdbusplus::com::intel::Control::server::convertForMessage(
2543 bmcSourceSignal));
Chen Yugang99be6332019-08-09 16:20:48 +08002544 // set Enabled property to inform NMI source handling
2545 // to trigger a NMI_OUT BSOD.
2546 // if it's triggered by NMI source property changed,
2547 // NMI_OUT BSOD could be missed if the same source occurs twice in a row
2548 if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None)
2549 {
2550 setDbusProperty(*dbus, service, oemNmiSourceObjPath,
2551 oemNmiSourceIntf, oemNmiEnabledObjPathProp,
2552 static_cast<bool>(true));
2553 }
Chen Yugang39736d52019-07-12 16:24:33 +08002554 }
2555 catch (sdbusplus::exception_t& e)
2556 {
2557 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2558 return ipmi::responseResponseError();
2559 }
2560
2561 return ipmi::responseSuccess();
2562}
2563
James Feist63efafa2019-07-24 12:39:21 -07002564namespace dimmOffset
2565{
2566constexpr const char* dimmPower = "DimmPower";
2567constexpr const char* staticCltt = "StaticCltt";
2568constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm";
2569constexpr const char* offsetInterface =
2570 "xyz.openbmc_project.Inventory.Item.Dimm.Offset";
2571constexpr const char* property = "DimmOffset";
2572
2573}; // namespace dimmOffset
2574
2575ipmi::RspType<>
2576 ipmiOEMSetDimmOffset(uint8_t type,
2577 const std::vector<std::tuple<uint8_t, uint8_t>>& data)
2578{
2579 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2580 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2581 {
2582 return ipmi::responseInvalidFieldRequest();
2583 }
2584
2585 if (data.empty())
2586 {
2587 return ipmi::responseInvalidFieldRequest();
2588 }
2589 nlohmann::json json;
2590
2591 std::ifstream jsonStream(dimmOffsetFile);
2592 if (jsonStream.good())
2593 {
2594 json = nlohmann::json::parse(jsonStream, nullptr, false);
2595 if (json.is_discarded())
2596 {
2597 json = nlohmann::json();
2598 }
2599 jsonStream.close();
2600 }
2601
2602 std::string typeName;
2603 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2604 {
2605 typeName = dimmOffset::dimmPower;
2606 }
2607 else
2608 {
2609 typeName = dimmOffset::staticCltt;
2610 }
2611
2612 nlohmann::json& field = json[typeName];
2613
2614 for (const auto& [index, value] : data)
2615 {
2616 field[index] = value;
2617 }
2618
2619 for (nlohmann::json& val : field)
2620 {
2621 if (val == nullptr)
2622 {
2623 val = static_cast<uint8_t>(0);
2624 }
2625 }
2626
2627 std::ofstream output(dimmOffsetFile);
2628 if (!output.good())
2629 {
2630 std::cerr << "Error writing json file\n";
2631 return ipmi::responseResponseError();
2632 }
2633
2634 output << json.dump(4);
2635
2636 if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2637 {
2638 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
2639
2640 std::variant<std::vector<uint8_t>> offsets =
2641 field.get<std::vector<uint8_t>>();
2642 auto call = bus->new_method_call(
2643 settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set");
2644 call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets);
2645 try
2646 {
2647 bus->call(call);
2648 }
2649 catch (sdbusplus::exception_t& e)
2650 {
2651 phosphor::logging::log<phosphor::logging::level::ERR>(
2652 "ipmiOEMSetDimmOffset: can't set dimm offsets!",
2653 phosphor::logging::entry("ERR=%s", e.what()));
2654 return ipmi::responseResponseError();
2655 }
2656 }
2657
2658 return ipmi::responseSuccess();
2659}
2660
2661ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index)
2662{
2663
2664 if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) &&
2665 type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt))
2666 {
2667 return ipmi::responseInvalidFieldRequest();
2668 }
2669
2670 std::ifstream jsonStream(dimmOffsetFile);
2671
2672 auto json = nlohmann::json::parse(jsonStream, nullptr, false);
2673 if (json.is_discarded())
2674 {
2675 std::cerr << "File error in " << dimmOffsetFile << "\n";
2676 return ipmi::responseResponseError();
2677 }
2678
2679 std::string typeName;
2680 if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower))
2681 {
2682 typeName = dimmOffset::dimmPower;
2683 }
2684 else
2685 {
2686 typeName = dimmOffset::staticCltt;
2687 }
2688
2689 auto it = json.find(typeName);
2690 if (it == json.end())
2691 {
2692 return ipmi::responseInvalidFieldRequest();
2693 }
2694
2695 if (it->size() <= index)
2696 {
2697 return ipmi::responseInvalidFieldRequest();
2698 }
2699
2700 uint8_t resp = it->at(index).get<uint8_t>();
2701 return ipmi::responseSuccess(resp);
2702}
2703
Jason M. Bills64796042018-10-03 16:51:55 -07002704static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002705{
2706 phosphor::logging::log<phosphor::logging::level::INFO>(
2707 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07002708 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
2709 ipmiOEMWildcard,
2710 PRIVILEGE_USER); // wildcard default handler
2711 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
2712 ipmiOEMWildcard,
2713 PRIVILEGE_USER); // wildcard default handler
2714 ipmiPrintAndRegister(
2715 netfnIntcOEMGeneral,
2716 static_cast<ipmi_cmd_t>(
2717 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
2718 NULL, ipmiOEMGetChassisIdentifier,
2719 PRIVILEGE_USER); // get chassis identifier
2720 ipmiPrintAndRegister(
2721 netfnIntcOEMGeneral,
2722 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
2723 NULL, ipmiOEMSetSystemGUID,
2724 PRIVILEGE_ADMIN); // set system guid
2725 ipmiPrintAndRegister(
2726 netfnIntcOEMGeneral,
2727 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
2728 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
2729 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2730 static_cast<ipmi_cmd_t>(
2731 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
2732 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
2733 ipmiPrintAndRegister(
2734 netfnIntcOEMGeneral,
2735 static_cast<ipmi_cmd_t>(
2736 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
2737 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08002738
2739 ipmi::registerHandler(
2740 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2741 static_cast<ipmi::Cmd>(
2742 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
2743 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
2744
Jason M. Bills64796042018-10-03 16:51:55 -07002745 ipmiPrintAndRegister(
2746 netfnIntcOEMGeneral,
2747 static_cast<ipmi_cmd_t>(
2748 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
2749 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
2750 ipmiPrintAndRegister(
2751 netfnIntcOEMGeneral,
2752 static_cast<ipmi_cmd_t>(
2753 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
2754 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05302755
2756 ipmi::registerHandler(
2757 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2758 static_cast<ipmi::Cmd>(
2759 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
2760 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
2761
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05302762 ipmi::registerHandler(
2763 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2764 static_cast<ipmi::Cmd>(
2765 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
2766 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
2767
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002768 // <Get Processor Error Config>
2769 ipmi::registerHandler(
2770 ipmi::prioOemBase, netfnIntcOEMGeneral,
2771 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07002772 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002773 ipmi::Privilege::User, ipmiOEMGetProcessorErrConfig);
2774 // <Set Processor Error Config>
2775 ipmi::registerHandler(
2776 ipmi::prioOemBase, netfnIntcOEMGeneral,
2777 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07002778 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002779 ipmi::Privilege::Admin, ipmiOEMSetProcessorErrConfig);
2780
Yong Li703922d2018-11-06 13:25:31 +08002781 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2782 static_cast<ipmi_cmd_t>(
2783 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
2784 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
2785 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2786 static_cast<ipmi_cmd_t>(
2787 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
2788 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08002789
2790 ipmiPrintAndRegister(
2791 netfnIntcOEMGeneral,
2792 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
2793 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
2794
James Feist5b693632019-07-09 09:06:09 -07002795 ipmi::registerHandler(
2796 ipmi::prioOemBase, netfnIntcOEMGeneral,
2797 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
2798 ipmi::Privilege::User, ipmiOEMGetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08002799
James Feistacc8a4e2019-04-02 14:23:57 -07002800 ipmi::registerHandler(
2801 ipmi::prioOemBase, netfnIntcOEMGeneral,
2802 static_cast<ipmi::Cmd>(
2803 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
2804 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07002805
James Feistacc8a4e2019-04-02 14:23:57 -07002806 ipmi::registerHandler(
2807 ipmi::prioOemBase, netfnIntcOEMGeneral,
2808 static_cast<ipmi::Cmd>(
2809 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
2810 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
2811
2812 ipmi::registerHandler(
2813 ipmi::prioOemBase, netfnIntcOEMGeneral,
2814 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
2815 ipmi::Privilege::User, ipmiOEMSetFscParameter);
2816
2817 ipmi::registerHandler(
2818 ipmi::prioOemBase, netfnIntcOEMGeneral,
2819 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
2820 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07002821
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302822 ipmi::registerHandler(
2823 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
2824 static_cast<ipmi::Cmd>(
2825 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId),
2826 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId);
2827
Chen Yugang39736d52019-07-12 16:24:33 +08002828 ipmi::registerHandler(
2829 ipmi::prioOemBase, netfnIntcOEMGeneral,
2830 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetNmiStatus),
2831 ipmi::Privilege::User, ipmiOEMGetNmiSource);
2832
2833 ipmi::registerHandler(
2834 ipmi::prioOemBase, netfnIntcOEMGeneral,
2835 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus),
2836 ipmi::Privilege::Operator, ipmiOEMSetNmiSource);
2837
Kuiying Wang45f04982018-12-26 09:23:08 +08002838 ipmiPrintAndRegister(
2839 netfnIntcOEMGeneral,
2840 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
2841 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08002842 ipmiPrintAndRegister(
2843 netfnIntcOEMPlatform,
2844 static_cast<ipmi_cmd_t>(
2845 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
2846 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002847 ipmi::registerHandler(
2848 ipmi::prioOemBase, netfnIntcOEMGeneral,
2849 static_cast<ipmi::Cmd>(
2850 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication),
2851 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002852
Cheng C Yang773703a2019-08-15 09:41:11 +08002853 ipmi::registerHandler(
2854 ipmi::prioOemBase, netfnIntcOEMGeneral,
2855 static_cast<ipmi::Cmd>(
2856 IPMINetfnIntelOEMGeneralCmd::cmdSetColdRedundancyConfig),
2857 ipmi::Privilege::User, ipmiOEMSetCRConfig);
2858 ipmi::registerHandler(
2859 ipmi::prioOemBase, netfnIntcOEMGeneral,
2860 static_cast<ipmi::Cmd>(
2861 IPMINetfnIntelOEMGeneralCmd::cmdGetColdRedundancyConfig),
2862 ipmi::Privilege::User, ipmiOEMGetCRConfig);
2863
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002864 registerHandler(prioOemBase, netfn::intel::oemGeneral,
2865 netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
2866 ipmiRestoreConfiguration);
James Feist63efafa2019-07-24 12:39:21 -07002867
2868 ipmi::registerHandler(
2869 ipmi::prioOemBase, netfnIntcOEMGeneral,
2870 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetDimmOffset),
2871 ipmi::Privilege::Operator, ipmiOEMSetDimmOffset);
2872
2873 ipmi::registerHandler(
2874 ipmi::prioOemBase, netfnIntcOEMGeneral,
2875 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetDimmOffset),
2876 ipmi::Privilege::Operator, ipmiOEMGetDimmOffset);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002877}
2878
2879} // namespace ipmi