blob: b6129488b1876240c7d3a82a3bf654dd0e12aafb [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>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080033#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <phosphor-logging/log.hpp>
35#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053036#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080037#include <string>
James Feist91244a62019-02-19 15:04:54 -080038#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080039#include <vector>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080040
41namespace ipmi
42{
Jason M. Bills64796042018-10-03 16:51:55 -070043static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070044
45namespace netfn::intel
46{
47constexpr NetFn oemGeneral = netFnOemOne;
48constexpr Cmd cmdRestoreConfiguration = 0x02;
49} // namespace netfn::intel
50
Jason M. Bills64796042018-10-03 16:51:55 -070051static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080052
Suryakanth Sekard509eb92018-11-15 17:44:11 +053053static constexpr auto ethernetIntf =
54 "xyz.openbmc_project.Network.EthernetInterface";
55static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
56static constexpr auto networkService = "xyz.openbmc_project.Network";
57static constexpr auto networkRoot = "/xyz/openbmc_project/network";
58
Chen Yugang39736d52019-07-12 16:24:33 +080059static constexpr const char* oemNmiSourceIntf = "com.intel.Control.NMISource";
60static constexpr const char* oemNmiSourceObjPath =
61 "/com/intel/control/NMISource";
62static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource";
63static constexpr const char* oemNmiEnabledObjPathProp = "Enabled";
64
65enum class NmiSource : uint8_t
66{
67 none = 0,
68 fpBtn = 1,
69 wdPreTimeout = 2,
70 pefMatch = 3,
71 chassisCmd = 4,
72 memoryError = 5,
73 pciSerrPerr = 6,
74 southbridgeNmi = 7,
75 chipsetNmi = 8,
76};
77
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080078// return code: 0 successful
79int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
80{
81 std::string objpath = "/xyz/openbmc_project/FruDevice";
82 std::string intf = "xyz.openbmc_project.FruDeviceManager";
83 std::string service = getService(bus, intf, objpath);
84 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
85 if (valueTree.empty())
86 {
87 phosphor::logging::log<phosphor::logging::level::ERR>(
88 "No object implements interface",
89 phosphor::logging::entry("INTF=%s", intf.c_str()));
90 return -1;
91 }
92
Jason M. Bills64796042018-10-03 16:51:55 -070093 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080094 {
95 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
96 if (interface == item.second.end())
97 {
98 continue;
99 }
100
101 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
102 if (property == interface->second.end())
103 {
104 continue;
105 }
106
107 try
108 {
109 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700110 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700111 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800112 {
113 phosphor::logging::log<phosphor::logging::level::ERR>(
114 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800115 return -1;
116 }
Jason M. Bills64796042018-10-03 16:51:55 -0700117 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800118 return 0;
119 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700120 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800121 {
Jason M. Bills64796042018-10-03 16:51:55 -0700122 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800123 return -1;
124 }
125 }
126 return -1;
127}
Jason M. Bills64796042018-10-03 16:51:55 -0700128
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800129ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
130 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700131 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800132{
Jason M. Bills64796042018-10-03 16:51:55 -0700133 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800134 // Status code.
135 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700136 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800137 return rc;
138}
139
140// Returns the Chassis Identifier (serial #)
141ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
142 ipmi_request_t request,
143 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700144 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800145 ipmi_context_t context)
146{
147 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700148 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800149 {
Jason M. Bills64796042018-10-03 16:51:55 -0700150 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800151 return IPMI_CC_REQ_DATA_LEN_INVALID;
152 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700153 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
154 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800155 {
Jason M. Bills64796042018-10-03 16:51:55 -0700156 *dataLen = serial.size(); // length will never exceed response length
157 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800158 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700159 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800160 return IPMI_CC_OK;
161 }
Jason M. Bills64796042018-10-03 16:51:55 -0700162 *dataLen = 0;
163 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800164}
165
166ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
167 ipmi_request_t request,
168 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700169 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800170{
171 static constexpr size_t safeBufferLength = 50;
172 char buf[safeBufferLength] = {0};
173 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
174
Jason M. Bills64796042018-10-03 16:51:55 -0700175 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800176 {
Jason M. Bills64796042018-10-03 16:51:55 -0700177 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800178 return IPMI_CC_REQ_DATA_LEN_INVALID;
179 }
180
Jason M. Bills64796042018-10-03 16:51:55 -0700181 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800182
183 snprintf(
184 buf, safeBufferLength,
185 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
186 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
187 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
188 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
189 Data->node3, Data->node2, Data->node1);
190 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
191 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800192
193 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
194 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700195 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
196 std::string service = getService(*dbus, intf, objpath);
197 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800198 return IPMI_CC_OK;
199}
200
201ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
202 ipmi_request_t request, ipmi_response_t response,
203 ipmi_data_len_t dataLen, ipmi_context_t context)
204{
205 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
206
Jason M. Bills64796042018-10-03 16:51:55 -0700207 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800208 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800209 *dataLen = 0;
210 return IPMI_CC_REQ_DATA_LEN_INVALID;
211 }
Jason M. Bills64796042018-10-03 16:51:55 -0700212 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800213
Vernon Mauery15419dd2019-05-24 09:40:30 -0700214 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
215 std::string service = getService(*dbus, biosIntf, biosObjPath);
216 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800217 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
218 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700219 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800220 *dataLen = 1;
221 return IPMI_CC_OK;
222}
223
224ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
225 ipmi_request_t request,
226 ipmi_response_t response,
227 ipmi_data_len_t dataLen, ipmi_context_t context)
228{
229 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
230 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
231
232 if (*dataLen == 0)
233 {
Jason M. Bills64796042018-10-03 16:51:55 -0700234 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800235 return IPMI_CC_REQ_DATA_LEN_INVALID;
236 }
237
238 size_t reqDataLen = *dataLen;
239 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700240 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800241 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800242 return IPMI_CC_INVALID_FIELD_REQUEST;
243 }
244
245 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700246 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800247 {
248 case OEMDevEntityType::biosId:
249 {
250 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
251 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800252 return IPMI_CC_REQ_DATA_LEN_INVALID;
253 }
254
Vernon Mauery15419dd2019-05-24 09:40:30 -0700255 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
256 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800257 try
258 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700259 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800260 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700261 std::string& idString = std::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800262 if (req->offset >= idString.size())
263 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800264 return IPMI_CC_PARM_OUT_OF_RANGE;
265 }
Jason M. Bills64796042018-10-03 16:51:55 -0700266 size_t length = 0;
267 if (req->countToRead > (idString.size() - req->offset))
268 {
269 length = idString.size() - req->offset;
270 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800271 else
272 {
Jason M. Bills64796042018-10-03 16:51:55 -0700273 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800274 }
Jason M. Bills64796042018-10-03 16:51:55 -0700275 std::copy(idString.begin() + req->offset, idString.end(),
276 res->data);
277 res->resDatalen = length;
278 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800279 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700280 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800281 {
Jason M. Bills64796042018-10-03 16:51:55 -0700282 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800283 return IPMI_CC_UNSPECIFIED_ERROR;
284 }
285 }
286 break;
287
288 case OEMDevEntityType::devVer:
289 case OEMDevEntityType::sdrVer:
290 // TODO:
291 return IPMI_CC_ILLEGAL_COMMAND;
292 default:
293 return IPMI_CC_INVALID_FIELD_REQUEST;
294 }
295 return IPMI_CC_OK;
296}
297
298ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
299 ipmi_request_t request, ipmi_response_t response,
300 ipmi_data_len_t dataLen, ipmi_context_t context)
301{
302 if (*dataLen != 0)
303 {
Jason M. Bills64796042018-10-03 16:51:55 -0700304 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800305 return IPMI_CC_REQ_DATA_LEN_INVALID;
306 }
307
308 *dataLen = 1;
309 uint8_t* res = reinterpret_cast<uint8_t*>(response);
310 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
311 // AIC is available so that BIOS will not timeout repeatly which leads to
312 // slow booting.
313 *res = 0; // Byte1=Count of SlotPosition/FruID records.
314 return IPMI_CC_OK;
315}
316
Jason M. Bills64796042018-10-03 16:51:55 -0700317ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
318 ipmi_request_t request,
319 ipmi_response_t response,
320 ipmi_data_len_t dataLen,
321 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800322{
Jason M. Bills64796042018-10-03 16:51:55 -0700323 GetPowerRestoreDelayRes* resp =
324 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
325
326 if (*dataLen != 0)
327 {
328 *dataLen = 0;
329 return IPMI_CC_REQ_DATA_LEN_INVALID;
330 }
331
Vernon Mauery15419dd2019-05-24 09:40:30 -0700332 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700333 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700334 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700335 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700336 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700337 powerRestoreDelayIntf, powerRestoreDelayProp);
338
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700339 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700340 resp->byteLSB = delay;
341 resp->byteMSB = delay >> 8;
342
343 *dataLen = sizeof(GetPowerRestoreDelayRes);
344
345 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800346}
347
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800348static uint8_t bcdToDec(uint8_t val)
349{
350 return ((val / 16 * 10) + (val % 16));
351}
352
353// Allows an update utility or system BIOS to send the status of an embedded
354// firmware update attempt to the BMC. After received, BMC will create a logging
355// record.
356ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
357 uint8_t majorRevision,
358 uint8_t minorRevision,
359 uint32_t auxInfo)
360{
361 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700362 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800363 target = (target & selEvtTargetMask) >> selEvtTargetShift;
364
365 /* make sure the status is 0, 1, or 2 as per the spec */
366 if (status > 2)
367 {
368 return ipmi::response(ipmi::ccInvalidFieldRequest);
369 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700370 /* make sure the target is 0, 1, 2, or 4 as per the spec */
371 if (target > 4 || target == 3)
372 {
373 return ipmi::response(ipmi::ccInvalidFieldRequest);
374 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800375 /*orignal OEM command is to record OEM SEL.
376 But openbmc does not support OEM SEL, so we redirect it to redfish event
377 logging. */
378 std::string buildInfo;
379 std::string action;
380 switch (FWUpdateTarget(target))
381 {
382 case FWUpdateTarget::targetBMC:
383 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700384 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800385 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
386 " BuildID: " + std::to_string(auxInfo);
387 buildInfo += std::to_string(auxInfo);
388 break;
389 case FWUpdateTarget::targetBIOS:
390 firmware = "BIOS";
391 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700392 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800393 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
394 " minor: " +
395 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
396 " ReleaseNumber: " + // ASCII encoded
397 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
398 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
399 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
400 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
401 break;
402 case FWUpdateTarget::targetME:
403 firmware = "ME";
404 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700405 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800406 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
407 " minor2: " +
408 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
409 " build1: " +
410 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
411 " build2: " +
412 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
413 break;
414 case FWUpdateTarget::targetOEMEWS:
415 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700416 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800417 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
418 " BuildID: " + std::to_string(auxInfo);
419 break;
420 }
421
Jason M. Billsdc249272019-04-03 09:58:40 -0700422 static const std::string openBMCMessageRegistryVersion("0.1");
423 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
424
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800425 switch (status)
426 {
427 case 0x0:
428 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700429 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800430 break;
431 case 0x1:
432 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700433 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800434 break;
435 case 0x2:
436 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700437 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800438 break;
439 default:
440 action = "unknown";
441 break;
442 }
443
Jason M. Billsdc249272019-04-03 09:58:40 -0700444 std::string firmwareInstanceStr =
445 firmware + " instance: " + std::to_string(instance);
446 std::string message("[firmware update] " + firmwareInstanceStr +
447 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800448
449 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700450 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
451 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
452 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800453 return ipmi::responseSuccess();
454}
455
Jason M. Bills64796042018-10-03 16:51:55 -0700456ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
457 ipmi_request_t request,
458 ipmi_response_t response,
459 ipmi_data_len_t dataLen,
460 ipmi_context_t context)
461{
462 SetPowerRestoreDelayReq* data =
463 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
464 uint16_t delay = 0;
465
466 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
467 {
468 *dataLen = 0;
469 return IPMI_CC_REQ_DATA_LEN_INVALID;
470 }
471 delay = data->byteMSB;
472 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700473 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700474 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700475 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
476 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700477 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
478 *dataLen = 0;
479
480 return IPMI_CC_OK;
481}
482
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700483static bool cpuPresent(const std::string& cpuName)
Jason M. Bills64796042018-10-03 16:51:55 -0700484{
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700485 static constexpr const char* cpuPresencePathPrefix =
486 "/xyz/openbmc_project/inventory/system/chassis/motherboard/";
487 static constexpr const char* cpuPresenceIntf =
488 "xyz.openbmc_project.Inventory.Item";
489 std::string cpuPresencePath = cpuPresencePathPrefix + cpuName;
490 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
491 try
Jason M. Bills64796042018-10-03 16:51:55 -0700492 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700493 auto service =
494 ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath);
495
496 ipmi::Value result = ipmi::getDbusProperty(
497 *busp, service, cpuPresencePath, cpuPresenceIntf, "Present");
498 return std::get<bool>(result);
499 }
500 catch (const std::exception& e)
501 {
502 phosphor::logging::log<phosphor::logging::level::INFO>(
503 "Cannot find processor presence",
504 phosphor::logging::entry("NAME=%s", cpuName.c_str()));
505 return false;
506 }
507}
508
509ipmi::RspType<bool, // CATERR Reset Enabled
510 bool, // ERR2 Reset Enabled
511 uint6_t, // reserved
512 uint8_t, // reserved, returns 0x3F
513 uint6_t, // CPU1 CATERR Count
514 uint2_t, // CPU1 Status
515 uint6_t, // CPU2 CATERR Count
516 uint2_t, // CPU2 Status
517 uint6_t, // CPU3 CATERR Count
518 uint2_t, // CPU3 Status
519 uint6_t, // CPU4 CATERR Count
520 uint2_t, // CPU4 Status
521 uint8_t // Crashdump Count
522 >
523 ipmiOEMGetProcessorErrConfig()
524{
525 bool resetOnCATERR = false;
526 bool resetOnERR2 = false;
527 uint6_t cpu1CATERRCount = 0;
528 uint6_t cpu2CATERRCount = 0;
529 uint6_t cpu3CATERRCount = 0;
530 uint6_t cpu4CATERRCount = 0;
531 uint8_t crashdumpCount = 0;
532 uint2_t cpu1Status =
533 cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent;
534 uint2_t cpu2Status =
535 cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent;
536 uint2_t cpu3Status =
537 cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent;
538 uint2_t cpu4Status =
539 cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent;
540
541 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
542 try
543 {
544 auto service = ipmi::getService(*busp, processorErrConfigIntf,
545 processorErrConfigObjPath);
546
547 ipmi::PropertyMap result = ipmi::getAllDbusProperties(
548 *busp, service, processorErrConfigObjPath, processorErrConfigIntf);
549 resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR"));
550 resetOnERR2 = std::get<bool>(result.at("ResetOnERR2"));
551 cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1"));
552 cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2"));
553 cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3"));
554 cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4"));
555 crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount"));
556 }
557 catch (const std::exception& e)
558 {
559 phosphor::logging::log<phosphor::logging::level::ERR>(
560 "Failed to fetch processor error config",
561 phosphor::logging::entry("ERROR=%s", e.what()));
562 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700563 }
564
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700565 return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F,
566 cpu1CATERRCount, cpu1Status, cpu2CATERRCount,
567 cpu2Status, cpu3CATERRCount, cpu3Status,
568 cpu4CATERRCount, cpu4Status, crashdumpCount);
569}
Jason M. Bills64796042018-10-03 16:51:55 -0700570
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700571ipmi::RspType<> ipmiOEMSetProcessorErrConfig(
572 bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2,
573 std::optional<bool> clearCPUErrorCount,
574 std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3)
575{
576 std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700577
578 try
579 {
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700580 auto service = ipmi::getService(*busp, processorErrConfigIntf,
581 processorErrConfigObjPath);
582 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
583 processorErrConfigIntf, "ResetOnCATERR",
584 resetOnCATERR);
585 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
586 processorErrConfigIntf, "ResetOnERR2",
587 resetOnERR2);
588 if (clearCPUErrorCount.value_or(false))
589 {
590 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
591 processorErrConfigIntf, "ErrorCountCPU1", 0);
592 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
593 processorErrConfigIntf, "ErrorCountCPU2", 0);
594 }
595 if (clearCrashdumpCount.value_or(false))
596 {
597 ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath,
598 processorErrConfigIntf, "CrashdumpCount", 0);
599 }
Jason M. Bills64796042018-10-03 16:51:55 -0700600 }
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700601 catch (std::exception& e)
Jason M. Bills64796042018-10-03 16:51:55 -0700602 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800603 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700604 "Failed to set processor error config",
605 phosphor::logging::entry("EXCEPTION=%s", e.what()));
606 return ipmi::responseUnspecifiedError();
Jason M. Bills64796042018-10-03 16:51:55 -0700607 }
608
Jason M. Bills42bd9c82019-06-28 16:39:34 -0700609 return ipmi::responseSuccess();
Jason M. Bills64796042018-10-03 16:51:55 -0700610}
611
Yong Li703922d2018-11-06 13:25:31 +0800612ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
613 ipmi_request_t request,
614 ipmi_response_t response,
615 ipmi_data_len_t dataLen,
616 ipmi_context_t context)
617{
618 GetOEMShutdownPolicyRes* resp =
619 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
620
621 if (*dataLen != 0)
622 {
623 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800624 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800625 *dataLen = 0;
626 return IPMI_CC_REQ_DATA_LEN_INVALID;
627 }
628
629 *dataLen = 0;
630
631 try
632 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700633 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800634 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700635 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
636 Value variant = getDbusProperty(
637 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
638 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800639
640 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
641 convertPolicyFromString(std::get<std::string>(variant)) ==
642 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
643 NoShutdownOnOCOT)
644 {
645 resp->policy = 0;
646 }
647 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
648 convertPolicyFromString(std::get<std::string>(variant)) ==
649 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
650 Policy::ShutdownOnOCOT)
651 {
652 resp->policy = 1;
653 }
654 else
655 {
656 phosphor::logging::log<phosphor::logging::level::ERR>(
657 "oem_set_shutdown_policy: invalid property!",
658 phosphor::logging::entry(
659 "PROP=%s", std::get<std::string>(variant).c_str()));
660 return IPMI_CC_UNSPECIFIED_ERROR;
661 }
Yong Li703922d2018-11-06 13:25:31 +0800662 // TODO needs to check if it is multi-node products,
663 // policy is only supported on node 3/4
664 resp->policySupport = shutdownPolicySupported;
665 }
666 catch (sdbusplus::exception_t& e)
667 {
668 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
669 return IPMI_CC_UNSPECIFIED_ERROR;
670 }
671
672 *dataLen = sizeof(GetOEMShutdownPolicyRes);
673 return IPMI_CC_OK;
674}
675
676ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
677 ipmi_request_t request,
678 ipmi_response_t response,
679 ipmi_data_len_t dataLen,
680 ipmi_context_t context)
681{
682 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800683 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
684 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
685 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800686
687 // TODO needs to check if it is multi-node products,
688 // policy is only supported on node 3/4
689 if (*dataLen != 1)
690 {
691 phosphor::logging::log<phosphor::logging::level::ERR>(
692 "oem_set_shutdown_policy: invalid input len!");
693 *dataLen = 0;
694 return IPMI_CC_REQ_DATA_LEN_INVALID;
695 }
696
697 *dataLen = 0;
698 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
699 {
700 phosphor::logging::log<phosphor::logging::level::ERR>(
701 "oem_set_shutdown_policy: invalid input!");
702 return IPMI_CC_INVALID_FIELD_REQUEST;
703 }
704
Yong Li0669d192019-05-06 14:01:46 +0800705 if (*req == noShutdownOnOCOT)
706 {
707 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
708 Policy::NoShutdownOnOCOT;
709 }
710 else
711 {
712 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
713 Policy::ShutdownOnOCOT;
714 }
715
Yong Li703922d2018-11-06 13:25:31 +0800716 try
717 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700718 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800719 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700720 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800721 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700722 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800723 oemShutdownPolicyObjPathProp,
724 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800725 }
726 catch (sdbusplus::exception_t& e)
727 {
728 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
729 return IPMI_CC_UNSPECIFIED_ERROR;
730 }
731
732 return IPMI_CC_OK;
733}
734
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530735/** @brief implementation for check the DHCP or not in IPv4
736 * @param[in] Channel - Channel number
737 * @returns true or false.
738 */
739static bool isDHCPEnabled(uint8_t Channel)
740{
741 try
742 {
743 auto ethdevice = getChannelName(Channel);
744 if (ethdevice.empty())
745 {
746 return false;
747 }
748 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700749 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530750 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700751 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
752 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530753 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700754 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530755 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
756 {
757 return true;
758 }
759 else
760 {
761 return false;
762 }
763 }
764 catch (sdbusplus::exception_t& e)
765 {
766 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
767 return true;
768 }
769}
770
771/** @brief implementes for check the DHCP or not in IPv6
772 * @param[in] Channel - Channel number
773 * @returns true or false.
774 */
775static bool isDHCPIPv6Enabled(uint8_t Channel)
776{
777
778 try
779 {
780 auto ethdevice = getChannelName(Channel);
781 if (ethdevice.empty())
782 {
783 return false;
784 }
785 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700786 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530787 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700788 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
789 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530790 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700791 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530792 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
793 {
794 return true;
795 }
796 else
797 {
798 return false;
799 }
800 }
801 catch (sdbusplus::exception_t& e)
802 {
803 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
804 return true;
805 }
806}
807
808/** @brief implementes the creating of default new user
809 * @param[in] userName - new username in 16 bytes.
810 * @param[in] userPassword - new password in 20 bytes
811 * @returns ipmi completion code.
812 */
813ipmi::RspType<> ipmiOEMSetUser2Activation(
814 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
815 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
816{
817 bool userState = false;
818 // Check for System Interface not exist and LAN should be static
819 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
820 {
821 ChannelInfo chInfo;
822 try
823 {
824 getChannelInfo(channel, chInfo);
825 }
826 catch (sdbusplus::exception_t& e)
827 {
828 phosphor::logging::log<phosphor::logging::level::ERR>(
829 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
830 phosphor::logging::entry("MSG: %s", e.description()));
831 return ipmi::response(ipmi::ccUnspecifiedError);
832 }
833 if (chInfo.mediumType ==
834 static_cast<uint8_t>(EChannelMediumType::systemInterface))
835 {
836 phosphor::logging::log<phosphor::logging::level::ERR>(
837 "ipmiOEMSetUser2Activation: system interface exist .");
838 return ipmi::response(ipmi::ccCommandNotAvailable);
839 }
840 else
841 {
842
843 if (chInfo.mediumType ==
844 static_cast<uint8_t>(EChannelMediumType::lan8032))
845 {
846 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
847 {
848 phosphor::logging::log<phosphor::logging::level::ERR>(
849 "ipmiOEMSetUser2Activation: DHCP enabled .");
850 return ipmi::response(ipmi::ccCommandNotAvailable);
851 }
852 }
853 }
854 }
855 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
856 if (ipmi::ccSuccess ==
857 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
858 {
859 if (enabledUsers > 1)
860 {
861 phosphor::logging::log<phosphor::logging::level::ERR>(
862 "ipmiOEMSetUser2Activation: more than one user is enabled.");
863 return ipmi::response(ipmi::ccCommandNotAvailable);
864 }
865 // Check the user 2 is enabled or not
866 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
867 if (userState == true)
868 {
869 phosphor::logging::log<phosphor::logging::level::ERR>(
870 "ipmiOEMSetUser2Activation: user 2 already enabled .");
871 return ipmi::response(ipmi::ccCommandNotAvailable);
872 }
873 }
874 else
875 {
876 return ipmi::response(ipmi::ccUnspecifiedError);
877 }
878
879#if BYTE_ORDER == LITTLE_ENDIAN
880 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
881#endif
882#if BYTE_ORDER == BIG_ENDIAN
883 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
884#endif
885
886 if (ipmi::ccSuccess ==
887 ipmiUserSetUserName(ipmiDefaultUserId,
888 reinterpret_cast<const char*>(userName.data())))
889 {
890 if (ipmi::ccSuccess ==
891 ipmiUserSetUserPassword(
892 ipmiDefaultUserId,
893 reinterpret_cast<const char*>(userPassword.data())))
894 {
895 if (ipmi::ccSuccess ==
896 ipmiUserSetPrivilegeAccess(
897 ipmiDefaultUserId,
898 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
899 privAccess, true))
900 {
901 phosphor::logging::log<phosphor::logging::level::INFO>(
902 "ipmiOEMSetUser2Activation: user created successfully ");
903 return ipmi::responseSuccess();
904 }
905 }
906 // we need to delete the default user id which added in this command as
907 // password / priv setting is failed.
908 ipmiUserSetUserName(ipmiDefaultUserId, "");
909 phosphor::logging::log<phosphor::logging::level::ERR>(
910 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
911 }
912 else
913 {
914 phosphor::logging::log<phosphor::logging::level::ERR>(
915 "ipmiOEMSetUser2Activation: Setting username failed.");
916 }
917
918 return ipmi::response(ipmi::ccCommandNotAvailable);
919}
920
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +0530921/** @brief implementes setting password for special user
922 * @param[in] specialUserIndex
923 * @param[in] userPassword - new password in 20 bytes
924 * @returns ipmi completion code.
925 */
926ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
927 uint8_t specialUserIndex,
928 std::vector<uint8_t> userPassword)
929{
930 ChannelInfo chInfo;
931 try
932 {
933 getChannelInfo(ctx->channel, chInfo);
934 }
935 catch (sdbusplus::exception_t& e)
936 {
937 phosphor::logging::log<phosphor::logging::level::ERR>(
938 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
939 phosphor::logging::entry("MSG: %s", e.description()));
940 return ipmi::responseUnspecifiedError();
941 }
942 if (chInfo.mediumType !=
943 static_cast<uint8_t>(EChannelMediumType::systemInterface))
944 {
945 phosphor::logging::log<phosphor::logging::level::ERR>(
946 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
947 "interface");
948 return ipmi::responseCommandNotAvailable();
949 }
950 if (specialUserIndex != 0)
951 {
952 phosphor::logging::log<phosphor::logging::level::ERR>(
953 "ipmiOEMSetSpecialUserPassword: Invalid user account");
954 return ipmi::responseParmOutOfRange();
955 }
956 constexpr uint8_t minPasswordSizeRequired = 6;
957 if (userPassword.size() < minPasswordSizeRequired ||
958 userPassword.size() > ipmi::maxIpmi20PasswordSize)
959 {
960 return ipmi::responseReqDataLenInvalid();
961 }
962 std::string passwd;
963 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
964 userPassword.size());
965 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
966}
967
Kuiying Wang45f04982018-12-26 09:23:08 +0800968namespace ledAction
969{
970using namespace sdbusplus::xyz::openbmc_project::Led::server;
971std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
972 {Physical::Action::Off, 0x00},
973 {Physical::Action::On, 0x10},
974 {Physical::Action::Blink, 0x01}};
975
976std::map<uint8_t, std::string> offsetObjPath = {
977 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
978
979} // namespace ledAction
980
981int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
982 const std::string& objPath, uint8_t& state)
983{
984 try
985 {
986 std::string service = getService(bus, intf, objPath);
987 Value stateValue =
988 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700989 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +0800990 state = ledAction::actionDbusToIpmi.at(
991 sdbusplus::xyz::openbmc_project::Led::server::Physical::
992 convertActionFromString(strState));
993 }
994 catch (sdbusplus::exception::SdBusError& e)
995 {
996 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
997 return -1;
998 }
999 return 0;
1000}
1001
1002ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1003 ipmi_request_t request, ipmi_response_t response,
1004 ipmi_data_len_t dataLen, ipmi_context_t context)
1005{
1006 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1007 // LED Status
1008 //[1:0] = Reserved
1009 //[3:2] = Status(Amber)
1010 //[5:4] = Status(Green)
1011 //[7:6] = System Identify
1012 // Status definitions:
1013 // 00b = Off
1014 // 01b = Blink
1015 // 10b = On
1016 // 11b = invalid
1017 if (*dataLen != 0)
1018 {
1019 phosphor::logging::log<phosphor::logging::level::ERR>(
1020 "oem_get_led_status: invalid input len!");
1021 *dataLen = 0;
1022 return IPMI_CC_REQ_DATA_LEN_INVALID;
1023 }
1024
1025 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
1026 *resp = 0;
1027 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001028 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +08001029 for (auto it = ledAction::offsetObjPath.begin();
1030 it != ledAction::offsetObjPath.end(); ++it)
1031 {
1032 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001033 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +08001034 {
1035 phosphor::logging::log<phosphor::logging::level::ERR>(
1036 "oem_get_led_status: fail to get ID LED status!");
1037 return IPMI_CC_UNSPECIFIED_ERROR;
1038 }
1039 *resp |= state << it->first;
1040 }
1041
1042 *dataLen = sizeof(*resp);
1043 return IPMI_CC_OK;
1044}
1045
Yong Li23737fe2019-02-19 08:49:55 +08001046ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1047 ipmi_request_t request,
1048 ipmi_response_t response,
1049 ipmi_data_len_t dataLen,
1050 ipmi_context_t context)
1051{
1052 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1053 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1054
1055 if (*dataLen == 0)
1056 {
1057 phosphor::logging::log<phosphor::logging::level::ERR>(
1058 "CfgHostSerial: invalid input len!",
1059 phosphor::logging::entry("LEN=%d", *dataLen));
1060 return IPMI_CC_REQ_DATA_LEN_INVALID;
1061 }
1062
1063 switch (req->command)
1064 {
1065 case getHostSerialCfgCmd:
1066 {
1067 if (*dataLen != 1)
1068 {
1069 phosphor::logging::log<phosphor::logging::level::ERR>(
1070 "CfgHostSerial: invalid input len!");
1071 *dataLen = 0;
1072 return IPMI_CC_REQ_DATA_LEN_INVALID;
1073 }
1074
1075 *dataLen = 0;
1076
1077 boost::process::ipstream is;
1078 std::vector<std::string> data;
1079 std::string line;
1080 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1081 boost::process::std_out > is);
1082
1083 while (c1.running() && std::getline(is, line) && !line.empty())
1084 {
1085 data.push_back(line);
1086 }
1087
1088 c1.wait();
1089 if (c1.exit_code())
1090 {
1091 phosphor::logging::log<phosphor::logging::level::ERR>(
1092 "CfgHostSerial:: error on execute",
1093 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1094 // Using the default value
1095 *resp = 0;
1096 }
1097 else
1098 {
1099 if (data.size() != 1)
1100 {
1101 phosphor::logging::log<phosphor::logging::level::ERR>(
1102 "CfgHostSerial:: error on read env");
1103 return IPMI_CC_UNSPECIFIED_ERROR;
1104 }
1105 try
1106 {
1107 unsigned long tmp = std::stoul(data[0]);
1108 if (tmp > std::numeric_limits<uint8_t>::max())
1109 {
1110 throw std::out_of_range("Out of range");
1111 }
1112 *resp = static_cast<uint8_t>(tmp);
1113 }
1114 catch (const std::invalid_argument& e)
1115 {
1116 phosphor::logging::log<phosphor::logging::level::ERR>(
1117 "invalid config ",
1118 phosphor::logging::entry("ERR=%s", e.what()));
1119 return IPMI_CC_UNSPECIFIED_ERROR;
1120 }
1121 catch (const std::out_of_range& e)
1122 {
1123 phosphor::logging::log<phosphor::logging::level::ERR>(
1124 "out_of_range config ",
1125 phosphor::logging::entry("ERR=%s", e.what()));
1126 return IPMI_CC_UNSPECIFIED_ERROR;
1127 }
1128 }
1129
1130 *dataLen = 1;
1131 break;
1132 }
1133 case setHostSerialCfgCmd:
1134 {
1135 if (*dataLen != sizeof(CfgHostSerialReq))
1136 {
1137 phosphor::logging::log<phosphor::logging::level::ERR>(
1138 "CfgHostSerial: invalid input len!");
1139 *dataLen = 0;
1140 return IPMI_CC_REQ_DATA_LEN_INVALID;
1141 }
1142
1143 *dataLen = 0;
1144
1145 if (req->parameter > HostSerialCfgParamMax)
1146 {
1147 phosphor::logging::log<phosphor::logging::level::ERR>(
1148 "CfgHostSerial: invalid input!");
1149 return IPMI_CC_INVALID_FIELD_REQUEST;
1150 }
1151
1152 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1153 std::to_string(req->parameter));
1154
1155 c1.wait();
1156 if (c1.exit_code())
1157 {
1158 phosphor::logging::log<phosphor::logging::level::ERR>(
1159 "CfgHostSerial:: error on execute",
1160 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1161 return IPMI_CC_UNSPECIFIED_ERROR;
1162 }
1163 break;
1164 }
1165 default:
1166 phosphor::logging::log<phosphor::logging::level::ERR>(
1167 "CfgHostSerial: invalid input!");
1168 *dataLen = 0;
1169 return IPMI_CC_INVALID_FIELD_REQUEST;
1170 }
1171
1172 return IPMI_CC_OK;
1173}
1174
James Feist91244a62019-02-19 15:04:54 -08001175constexpr const char* thermalModeInterface =
1176 "xyz.openbmc_project.Control.ThermalMode";
1177constexpr const char* thermalModePath =
1178 "/xyz/openbmc_project/control/thermal_mode";
1179
1180bool getFanProfileInterface(
1181 sdbusplus::bus::bus& bus,
1182 boost::container::flat_map<
1183 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1184{
1185 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1186 "GetAll");
1187 call.append(thermalModeInterface);
1188 try
1189 {
1190 auto data = bus.call(call);
1191 data.read(resp);
1192 }
1193 catch (sdbusplus::exception_t& e)
1194 {
1195 phosphor::logging::log<phosphor::logging::level::ERR>(
1196 "getFanProfileInterface: can't get thermal mode!",
1197 phosphor::logging::entry("ERR=%s", e.what()));
1198 return false;
1199 }
1200 return true;
1201}
1202
1203ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1204 ipmi_request_t request, ipmi_response_t response,
1205 ipmi_data_len_t dataLen, ipmi_context_t context)
1206{
1207
1208 if (*dataLen < 2 || *dataLen > 7)
1209 {
1210 phosphor::logging::log<phosphor::logging::level::ERR>(
1211 "ipmiOEMSetFanConfig: invalid input len!");
1212 *dataLen = 0;
1213 return IPMI_CC_REQ_DATA_LEN_INVALID;
1214 }
1215
1216 // todo: tell bios to only send first 2 bytes
1217
1218 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1219 boost::container::flat_map<
1220 std::string, std::variant<std::vector<std::string>, std::string>>
1221 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001222 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1223 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001224 {
1225 return IPMI_CC_UNSPECIFIED_ERROR;
1226 }
1227
1228 std::vector<std::string>* supported =
1229 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1230 if (supported == nullptr)
1231 {
1232 return IPMI_CC_INVALID_FIELD_REQUEST;
1233 }
1234 std::string mode;
1235 if (req->flags &
1236 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1237 {
1238 bool performanceMode =
1239 (req->flags & (1 << static_cast<uint8_t>(
1240 setFanProfileFlags::performAcousSelect))) > 0;
1241
1242 if (performanceMode)
1243 {
1244
1245 if (std::find(supported->begin(), supported->end(),
1246 "Performance") != supported->end())
1247 {
1248 mode = "Performance";
1249 }
1250 }
1251 else
1252 {
1253
1254 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1255 supported->end())
1256 {
1257 mode = "Acoustic";
1258 }
1259 }
1260 if (mode.empty())
1261 {
1262 return IPMI_CC_INVALID_FIELD_REQUEST;
1263 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001264 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001265 thermalModeInterface, "Current", mode);
1266 }
1267
1268 return IPMI_CC_OK;
1269}
1270
James Feist5b693632019-07-09 09:06:09 -07001271ipmi::RspType<uint8_t, // profile support map
1272 uint8_t, // fan control profile enable
1273 uint8_t, // flags
1274 uint32_t // dimm presence bit map
1275 >
1276 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001277{
James Feist91244a62019-02-19 15:04:54 -08001278 boost::container::flat_map<
1279 std::string, std::variant<std::vector<std::string>, std::string>>
1280 profileData;
1281
Vernon Mauery15419dd2019-05-24 09:40:30 -07001282 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1283 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001284 {
James Feist5b693632019-07-09 09:06:09 -07001285 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001286 }
1287
1288 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1289
1290 if (current == nullptr)
1291 {
1292 phosphor::logging::log<phosphor::logging::level::ERR>(
1293 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001294 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001295 }
1296 bool performance = (*current == "Performance");
1297
James Feist5b693632019-07-09 09:06:09 -07001298 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001299 if (performance)
1300 {
James Feist5b693632019-07-09 09:06:09 -07001301 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001302 }
1303
James Feist5b693632019-07-09 09:06:09 -07001304 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001305}
James Feist5f957ca2019-03-14 15:33:55 -07001306constexpr const char* cfmLimitSettingPath =
1307 "/xyz/openbmc_project/control/cfm_limit";
1308constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001309constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feistacc8a4e2019-04-02 14:23:57 -07001310constexpr const char* pidConfigurationIface =
1311 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001312
1313static std::string getExitAirConfigPath()
1314{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001315 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001316 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001317 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1318 "/xyz/openbmc_project/object_mapper",
1319 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001320
James Feistacc8a4e2019-04-02 14:23:57 -07001321 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001322 std::string path;
1323 GetSubTreeType resp;
1324 try
1325 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001326 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001327 reply.read(resp);
1328 }
1329 catch (sdbusplus::exception_t&)
1330 {
1331 phosphor::logging::log<phosphor::logging::level::ERR>(
1332 "ipmiOEMGetFscParameter: mapper error");
1333 };
1334 auto config = std::find_if(resp.begin(), resp.end(), [](const auto& pair) {
1335 return pair.first.find("Exit_Air") != std::string::npos;
1336 });
1337 if (config != resp.end())
1338 {
1339 path = std::move(config->first);
1340 }
1341 return path;
1342}
James Feist5f957ca2019-03-14 15:33:55 -07001343
James Feistacc8a4e2019-04-02 14:23:57 -07001344// flat map to make alphabetical
1345static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1346{
1347 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001348 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001349 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001350 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1351 "/xyz/openbmc_project/object_mapper",
1352 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001353
1354 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1355 GetSubTreeType resp;
1356
1357 try
1358 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001359 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001360 reply.read(resp);
1361 }
1362 catch (sdbusplus::exception_t&)
1363 {
1364 phosphor::logging::log<phosphor::logging::level::ERR>(
1365 "getFanConfigPaths: mapper error");
1366 };
1367 for (const auto& [path, objects] : resp)
1368 {
1369 if (objects.empty())
1370 {
1371 continue; // should be impossible
1372 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001373
1374 try
1375 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001376 ret.emplace(path,
1377 getAllDbusProperties(*dbus, objects[0].first, path,
1378 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001379 }
1380 catch (sdbusplus::exception_t& e)
1381 {
1382 phosphor::logging::log<phosphor::logging::level::ERR>(
1383 "getPidConfigs: can't get DbusProperties!",
1384 phosphor::logging::entry("ERR=%s", e.what()));
1385 }
James Feistacc8a4e2019-04-02 14:23:57 -07001386 }
1387 return ret;
1388}
1389
1390ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1391{
1392 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1393 if (data.empty())
1394 {
1395 return ipmi::responseResponseError();
1396 }
1397 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1398 for (const auto& [_, pid] : data)
1399 {
1400 auto findClass = pid.find("Class");
1401 if (findClass == pid.end())
1402 {
1403 phosphor::logging::log<phosphor::logging::level::ERR>(
1404 "ipmiOEMGetFscParameter: found illegal pid "
1405 "configurations");
1406 return ipmi::responseResponseError();
1407 }
1408 std::string type = std::get<std::string>(findClass->second);
1409 if (type == "fan")
1410 {
1411 auto findOutLimit = pid.find("OutLimitMin");
1412 if (findOutLimit == pid.end())
1413 {
1414 phosphor::logging::log<phosphor::logging::level::ERR>(
1415 "ipmiOEMGetFscParameter: found illegal pid "
1416 "configurations");
1417 return ipmi::responseResponseError();
1418 }
1419 // get the min out of all the offsets
1420 minOffset = std::min(
1421 minOffset,
1422 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1423 }
1424 }
1425 if (minOffset == std::numeric_limits<uint8_t>::max())
1426 {
1427 phosphor::logging::log<phosphor::logging::level::ERR>(
1428 "ipmiOEMGetFscParameter: found no fan configurations!");
1429 return ipmi::responseResponseError();
1430 }
1431
1432 return ipmi::responseSuccess(minOffset);
1433}
1434
1435ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1436{
1437 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1438 if (data.empty())
1439 {
1440
1441 phosphor::logging::log<phosphor::logging::level::ERR>(
1442 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1443 return ipmi::responseResponseError();
1444 }
1445
Vernon Mauery15419dd2019-05-24 09:40:30 -07001446 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001447 bool found = false;
1448 for (const auto& [path, pid] : data)
1449 {
1450 auto findClass = pid.find("Class");
1451 if (findClass == pid.end())
1452 {
1453
1454 phosphor::logging::log<phosphor::logging::level::ERR>(
1455 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1456 "configurations");
1457 return ipmi::responseResponseError();
1458 }
1459 std::string type = std::get<std::string>(findClass->second);
1460 if (type == "fan")
1461 {
1462 auto findOutLimit = pid.find("OutLimitMin");
1463 if (findOutLimit == pid.end())
1464 {
1465
1466 phosphor::logging::log<phosphor::logging::level::ERR>(
1467 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1468 "configurations");
1469 return ipmi::responseResponseError();
1470 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001471 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001472 path, pidConfigurationIface, "OutLimitMin",
1473 static_cast<double>(offset));
1474 found = true;
1475 }
1476 }
1477 if (!found)
1478 {
1479 phosphor::logging::log<phosphor::logging::level::ERR>(
1480 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1481 return ipmi::responseResponseError();
1482 }
1483
1484 return ipmi::responseSuccess();
1485}
1486
1487ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1488 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001489{
1490 constexpr const size_t disableLimiting = 0x0;
1491
Vernon Mauery15419dd2019-05-24 09:40:30 -07001492 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001493 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001494 {
James Feistacc8a4e2019-04-02 14:23:57 -07001495 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001496 {
James Feistfaa4f222019-03-21 16:21:55 -07001497 std::string path = getExitAirConfigPath();
Vernon Mauery15419dd2019-05-24 09:40:30 -07001498 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001499 path, pidConfigurationIface, "SetPoint",
1500 static_cast<double>(param2));
1501 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001502 }
1503 else
1504 {
James Feistacc8a4e2019-04-02 14:23:57 -07001505 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001506 }
1507 }
James Feistacc8a4e2019-04-02 14:23:57 -07001508 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001509 {
James Feistacc8a4e2019-04-02 14:23:57 -07001510 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001511
1512 // must be greater than 50 based on eps
1513 if (cfm < 50 && cfm != disableLimiting)
1514 {
James Feistacc8a4e2019-04-02 14:23:57 -07001515 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001516 }
1517
1518 try
1519 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001520 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001521 cfmLimitIface, "Limit",
1522 static_cast<double>(cfm));
1523 }
1524 catch (sdbusplus::exception_t& e)
1525 {
1526 phosphor::logging::log<phosphor::logging::level::ERR>(
1527 "ipmiOEMSetFscParameter: can't set cfm setting!",
1528 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001529 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001530 }
James Feistacc8a4e2019-04-02 14:23:57 -07001531 return ipmi::responseSuccess();
1532 }
1533 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1534 {
1535 constexpr const size_t maxDomainCount = 8;
1536 uint8_t requestedDomainMask = param1;
1537 boost::container::flat_map data = getPidConfigs();
1538 if (data.empty())
1539 {
1540
1541 phosphor::logging::log<phosphor::logging::level::ERR>(
1542 "ipmiOEMSetFscParameter: found no pid configurations!");
1543 return ipmi::responseResponseError();
1544 }
1545 size_t count = 0;
1546 for (const auto& [path, pid] : data)
1547 {
1548 auto findClass = pid.find("Class");
1549 if (findClass == pid.end())
1550 {
1551
1552 phosphor::logging::log<phosphor::logging::level::ERR>(
1553 "ipmiOEMSetFscParameter: found illegal pid "
1554 "configurations");
1555 return ipmi::responseResponseError();
1556 }
1557 std::string type = std::get<std::string>(findClass->second);
1558 if (type == "fan")
1559 {
1560 if (requestedDomainMask & (1 << count))
1561 {
1562 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001563 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001564 pidConfigurationIface, "OutLimitMax",
1565 static_cast<double>(param2));
1566 }
1567 count++;
1568 }
1569 }
1570 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001571 }
1572 else
1573 {
1574 // todo other command parts possibly
1575 // tcontrol is handled in peci now
1576 // fan speed offset not implemented yet
1577 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001578 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001579 }
1580}
1581
James Feistacc8a4e2019-04-02 14:23:57 -07001582ipmi::RspType<
1583 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1584 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001585{
James Feistfaa4f222019-03-21 16:21:55 -07001586 constexpr uint8_t legacyDefaultExitAirLimit = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001587
Vernon Mauery15419dd2019-05-24 09:40:30 -07001588 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001589 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001590 {
James Feistacc8a4e2019-04-02 14:23:57 -07001591 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001592 {
James Feistacc8a4e2019-04-02 14:23:57 -07001593 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001594 }
1595
James Feistacc8a4e2019-04-02 14:23:57 -07001596 if (*param != legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001597 {
James Feistacc8a4e2019-04-02 14:23:57 -07001598 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001599 }
1600 uint8_t setpoint = legacyDefaultExitAirLimit;
1601 std::string path = getExitAirConfigPath();
1602 if (path.size())
1603 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001604 Value val = ipmi::getDbusProperty(
1605 *dbus, "xyz.openbmc_project.EntityManager", path,
1606 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001607 setpoint = std::floor(std::get<double>(val) + 0.5);
1608 }
1609
1610 // old implementation used to return the "default" and current, we
1611 // don't make the default readily available so just make both the
1612 // same
James Feistfaa4f222019-03-21 16:21:55 -07001613
James Feistacc8a4e2019-04-02 14:23:57 -07001614 return ipmi::responseSuccess(
1615 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001616 }
James Feistacc8a4e2019-04-02 14:23:57 -07001617 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1618 {
1619 constexpr const size_t maxDomainCount = 8;
1620
1621 if (!param)
1622 {
1623 return ipmi::responseReqDataLenInvalid();
1624 }
1625 uint8_t requestedDomain = *param;
1626 if (requestedDomain >= maxDomainCount)
1627 {
1628 return ipmi::responseInvalidFieldRequest();
1629 }
1630
1631 boost::container::flat_map data = getPidConfigs();
1632 if (data.empty())
1633 {
1634 phosphor::logging::log<phosphor::logging::level::ERR>(
1635 "ipmiOEMGetFscParameter: found no pid configurations!");
1636 return ipmi::responseResponseError();
1637 }
1638 size_t count = 0;
1639 for (const auto& [_, pid] : data)
1640 {
1641 auto findClass = pid.find("Class");
1642 if (findClass == pid.end())
1643 {
1644 phosphor::logging::log<phosphor::logging::level::ERR>(
1645 "ipmiOEMGetFscParameter: found illegal pid "
1646 "configurations");
1647 return ipmi::responseResponseError();
1648 }
1649 std::string type = std::get<std::string>(findClass->second);
1650 if (type == "fan")
1651 {
1652 if (requestedDomain == count)
1653 {
1654 auto findOutLimit = pid.find("OutLimitMax");
1655 if (findOutLimit == pid.end())
1656 {
1657 phosphor::logging::log<phosphor::logging::level::ERR>(
1658 "ipmiOEMGetFscParameter: found illegal pid "
1659 "configurations");
1660 return ipmi::responseResponseError();
1661 }
1662
1663 return ipmi::responseSuccess(
1664 static_cast<uint8_t>(std::floor(
1665 std::get<double>(findOutLimit->second) + 0.5)));
1666 }
1667 else
1668 {
1669 count++;
1670 }
1671 }
1672 }
1673
1674 return ipmi::responseInvalidFieldRequest();
1675 }
1676 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001677 {
1678
1679 /*
1680 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001681 previous behavior didn't seem to prevent this, ignore the check for
1682 now.
James Feist5f957ca2019-03-14 15:33:55 -07001683
James Feistacc8a4e2019-04-02 14:23:57 -07001684 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001685 {
1686 phosphor::logging::log<phosphor::logging::level::ERR>(
1687 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001688 return IPMI_CC_REQ_DATA_LEN_INVALID;
1689 }
1690 */
1691 Value cfmLimit;
1692 Value cfmMaximum;
1693 try
1694 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001695 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001696 cfmLimitSettingPath, cfmLimitIface,
1697 "Limit");
1698 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001699 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001700 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1701 }
1702 catch (sdbusplus::exception_t& e)
1703 {
1704 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001705 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001706 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001707 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001708 }
1709
James Feistacc8a4e2019-04-02 14:23:57 -07001710 double cfmMax = std::get<double>(cfmMaximum);
1711 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001712
James Feistacc8a4e2019-04-02 14:23:57 -07001713 cfmLim = std::floor(cfmLim + 0.5);
1714 cfmMax = std::floor(cfmMax + 0.5);
1715 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1716 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001717
James Feistacc8a4e2019-04-02 14:23:57 -07001718 return ipmi::responseSuccess(
1719 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001720 }
James Feistacc8a4e2019-04-02 14:23:57 -07001721
James Feist5f957ca2019-03-14 15:33:55 -07001722 else
1723 {
1724 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001725 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001726 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001727 }
1728}
1729
Zhu, Yungebe560b02019-04-21 21:19:21 -04001730ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
1731 uint8_t faultState,
1732 uint8_t faultGroup,
1733 std::array<uint8_t, 8>& ledStateData)
1734{
1735 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
1736 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
1737 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
1738 static const std::array<std::string, maxFaultType> faultNames = {
1739 "faultFan", "faultTemp", "faultPower",
1740 "faultDriveSlot", "faultSoftware", "faultMemory"};
1741 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
1742 static constexpr const char* postfixValue = "/value";
1743
1744 constexpr uint8_t maxFaultSource = 0x4;
1745 constexpr uint8_t skipLEDs = 0xFF;
1746 constexpr uint8_t pinSize = 64;
1747 constexpr uint8_t groupSize = 16;
1748
1749 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
1750 uint64_t resFIndex = 0;
1751 std::string resFType;
1752 std::string service;
1753 ObjectValueTree valueTree;
1754
1755 // Validate the source, fault type
1756 if ((sourceId >= maxFaultSource) ||
1757 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
1758 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
1759 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
1760 {
1761 return ipmi::responseParmOutOfRange();
1762 }
1763
Vernon Mauery15419dd2019-05-24 09:40:30 -07001764 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04001765 try
1766 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001767 service = getService(*dbus, intf, objpath);
1768 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04001769 }
1770 catch (const std::exception& e)
1771 {
1772 phosphor::logging::log<phosphor::logging::level::ERR>(
1773 "No object implements interface",
1774 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1775 phosphor::logging::entry("INTF=%s", intf));
1776 return ipmi::responseResponseError();
1777 }
1778
1779 if (valueTree.empty())
1780 {
1781 phosphor::logging::log<phosphor::logging::level::ERR>(
1782 "No object implements interface",
1783 phosphor::logging::entry("INTF=%s", intf));
1784 return ipmi::responseResponseError();
1785 }
1786
1787 for (const auto& item : valueTree)
1788 {
1789 // find LedFault configuration
1790 auto interface =
1791 item.second.find("xyz.openbmc_project.Configuration.LedFault");
1792 if (interface == item.second.end())
1793 {
1794 continue;
1795 }
1796
1797 // find matched fault type: faultMemmory / faultFan
1798 // find LedGpioPins/FaultIndex configuration
1799 auto propertyFaultType = interface->second.find("FaultType");
1800 auto propertyFIndex = interface->second.find("FaultIndex");
1801 auto ledIndex = interface->second.find("LedGpioPins");
1802
1803 if (propertyFaultType == interface->second.end() ||
1804 propertyFIndex == interface->second.end() ||
1805 ledIndex == interface->second.end())
1806 {
1807 continue;
1808 }
1809
1810 try
1811 {
1812 Value valIndex = propertyFIndex->second;
1813 resFIndex = std::get<uint64_t>(valIndex);
1814
1815 Value valFType = propertyFaultType->second;
1816 resFType = std::get<std::string>(valFType);
1817 }
1818 catch (const std::bad_variant_access& e)
1819 {
1820 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1821 return ipmi::responseResponseError();
1822 }
1823 // find the matched requested fault type: faultMemmory or faultFan
1824 if (resFType != faultNames[faultType])
1825 {
1826 continue;
1827 }
1828
1829 // read LedGpioPins data
1830 std::vector<uint64_t> ledgpios;
1831 std::variant<std::vector<uint64_t>> message;
1832
Vernon Mauery15419dd2019-05-24 09:40:30 -07001833 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04001834 service.c_str(), (std::string(item.first)).c_str(),
1835 "org.freedesktop.DBus.Properties", "Get");
1836
1837 method.append("xyz.openbmc_project.Configuration.LedFault",
1838 "LedGpioPins");
1839
1840 try
1841 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001842 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04001843 reply.read(message);
1844 ledgpios = std::get<std::vector<uint64_t>>(message);
1845 }
1846 catch (std::exception& e)
1847 {
1848 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1849 return ipmi::responseResponseError();
1850 }
1851
1852 // Check the size to be sure it will never overflow on groupSize
1853 if (ledgpios.size() > groupSize)
1854 {
1855 phosphor::logging::log<phosphor::logging::level::ERR>(
1856 "Fault gpio Pins out of range!");
1857 return ipmi::responseParmOutOfRange();
1858 }
1859 // Store data, according to command data bit index order
1860 for (int i = 0; i < ledgpios.size(); i++)
1861 {
1862 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
1863 }
1864 }
1865
1866 switch (RemoteFaultType(faultType))
1867 {
1868 case (RemoteFaultType::fan):
1869 case (RemoteFaultType::memory):
1870 {
1871 if (faultGroup == skipLEDs)
1872 {
1873 return ipmi::responseSuccess();
1874 }
1875
1876 uint64_t ledState = 0;
1877 // calculate led state bit filed count, each byte has 8bits
1878 // the maximum bits will be 8 * 8 bits
1879 constexpr uint8_t size = sizeof(ledStateData) * 8;
1880 for (int i = 0; i < sizeof(ledStateData); i++)
1881 {
1882 ledState = (uint64_t)(ledState << 8);
1883 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
1884 }
1885
1886 std::bitset<size> ledStateBits(ledState);
1887 std::string gpioValue;
1888 for (int i = 0; i < size; i++)
1889 { // skip invalid value
1890 if (ledFaultPins[i] == 0xFFFF)
1891 {
1892 continue;
1893 }
1894
1895 std::string device = sysGpioPath +
1896 std::to_string(ledFaultPins[i]) +
1897 postfixValue;
1898 std::fstream gpioFile;
1899
1900 gpioFile.open(device, std::ios::out);
1901
1902 if (!gpioFile.good())
1903 {
1904 phosphor::logging::log<phosphor::logging::level::ERR>(
1905 "Not Find Led Gpio Device!",
1906 phosphor::logging::entry("DEVICE=%s", device.c_str()));
1907 return ipmi::responseResponseError();
1908 }
1909 gpioFile << std::to_string(
1910 static_cast<uint8_t>(ledStateBits[i]));
1911 gpioFile.close();
1912 }
1913 break;
1914 }
1915 default:
1916 {
1917 // now only support two fault types
1918 return ipmi::responseParmOutOfRange();
1919 }
1920 }
1921
1922 return ipmi::responseSuccess();
1923}
1924
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301925ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
1926{
1927 uint8_t prodId = 0;
1928 try
1929 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001930 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301931 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001932 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301933 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
1934 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001935 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301936 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
1937 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
1938 }
1939 catch (std::exception& e)
1940 {
1941 phosphor::logging::log<phosphor::logging::level::ERR>(
1942 "ipmiOEMReadBoardProductId: Product ID read failed!",
1943 phosphor::logging::entry("ERR=%s", e.what()));
1944 }
1945 return ipmi::responseSuccess(prodId);
1946}
1947
Vernon Mauery4ac799d2019-05-20 15:50:37 -07001948ipmi::RspType<uint8_t /* restore status */>
1949 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
1950{
1951 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
1952
1953 if (clr != expClr)
1954 {
1955 return ipmi::responseInvalidFieldRequest();
1956 }
1957 constexpr uint8_t cmdStatus = 0;
1958 constexpr uint8_t cmdDefaultRestore = 0xaa;
1959 constexpr uint8_t cmdFullRestore = 0xbb;
1960 constexpr uint8_t cmdFormat = 0xcc;
1961
1962 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
1963
1964 switch (cmd)
1965 {
1966 case cmdStatus:
1967 break;
1968 case cmdDefaultRestore:
1969 case cmdFullRestore:
1970 case cmdFormat:
1971 {
1972 // write file to rwfs root
1973 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
1974 std::ofstream restoreFile(restoreOpFname);
1975 if (!restoreFile)
1976 {
1977 return ipmi::responseUnspecifiedError();
1978 }
1979 restoreFile << value << "\n";
1980 break;
1981 }
1982 default:
1983 return ipmi::responseInvalidFieldRequest();
1984 }
1985
1986 constexpr uint8_t restorePending = 0;
1987 constexpr uint8_t restoreComplete = 1;
1988
1989 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
1990 ? restorePending
1991 : restoreComplete;
1992 return ipmi::responseSuccess(restoreStatus);
1993}
1994
Chen Yugang39736d52019-07-12 16:24:33 +08001995ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
1996{
1997 uint8_t bmcSource;
1998 namespace nmi = sdbusplus::com::intel::Control::server;
1999
2000 try
2001 {
2002 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2003 std::string service =
2004 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2005 Value variant =
2006 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
2007 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
2008
2009 switch (nmi::NMISource::convertBMCSourceSignalFromString(
2010 std::get<std::string>(variant)))
2011 {
2012 case nmi::NMISource::BMCSourceSignal::None:
2013 bmcSource = static_cast<uint8_t>(NmiSource::none);
2014 break;
2015 case nmi::NMISource::BMCSourceSignal::FpBtn:
2016 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
2017 break;
2018 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
2019 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
2020 break;
2021 case nmi::NMISource::BMCSourceSignal::PefMatch:
2022 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
2023 break;
2024 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
2025 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
2026 break;
2027 case nmi::NMISource::BMCSourceSignal::MemoryError:
2028 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
2029 break;
2030 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
2031 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
2032 break;
2033 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
2034 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
2035 break;
2036 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
2037 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
2038 break;
2039 default:
2040 phosphor::logging::log<phosphor::logging::level::ERR>(
2041 "NMI source: invalid property!",
2042 phosphor::logging::entry(
2043 "PROP=%s", std::get<std::string>(variant).c_str()));
2044 return ipmi::responseResponseError();
2045 }
2046 }
2047 catch (sdbusplus::exception::SdBusError& e)
2048 {
2049 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2050 return ipmi::responseResponseError();
2051 }
2052
2053 return ipmi::responseSuccess(bmcSource);
2054}
2055
2056ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2057{
2058 namespace nmi = sdbusplus::com::intel::Control::server;
2059
2060 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2061 nmi::NMISource::BMCSourceSignal::None;
2062
2063 switch (NmiSource(sourceId))
2064 {
2065 case NmiSource::none:
2066 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2067 break;
2068 case NmiSource::fpBtn:
2069 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2070 break;
2071 case NmiSource::wdPreTimeout:
2072 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2073 break;
2074 case NmiSource::pefMatch:
2075 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2076 break;
2077 case NmiSource::chassisCmd:
2078 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2079 break;
2080 case NmiSource::memoryError:
2081 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2082 break;
2083 case NmiSource::pciSerrPerr:
2084 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2085 break;
2086 case NmiSource::southbridgeNmi:
2087 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2088 break;
2089 case NmiSource::chipsetNmi:
2090 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2091 break;
2092 default:
2093 phosphor::logging::log<phosphor::logging::level::ERR>(
2094 "NMI source: invalid property!");
2095 return ipmi::responseResponseError();
2096 }
2097
2098 try
2099 {
2100 // keep NMI signal source
2101 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2102 std::string service =
2103 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2104 setDbusProperty(
2105 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2106 oemNmiBmcSourceObjPathProp,
2107 sdbusplus::com::intel::Control::server::convertForMessage(
2108 bmcSourceSignal));
2109 }
2110 catch (sdbusplus::exception_t& e)
2111 {
2112 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2113 return ipmi::responseResponseError();
2114 }
2115
2116 return ipmi::responseSuccess();
2117}
2118
Jason M. Bills64796042018-10-03 16:51:55 -07002119static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002120{
2121 phosphor::logging::log<phosphor::logging::level::INFO>(
2122 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07002123 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
2124 ipmiOEMWildcard,
2125 PRIVILEGE_USER); // wildcard default handler
2126 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
2127 ipmiOEMWildcard,
2128 PRIVILEGE_USER); // wildcard default handler
2129 ipmiPrintAndRegister(
2130 netfnIntcOEMGeneral,
2131 static_cast<ipmi_cmd_t>(
2132 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
2133 NULL, ipmiOEMGetChassisIdentifier,
2134 PRIVILEGE_USER); // get chassis identifier
2135 ipmiPrintAndRegister(
2136 netfnIntcOEMGeneral,
2137 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
2138 NULL, ipmiOEMSetSystemGUID,
2139 PRIVILEGE_ADMIN); // set system guid
2140 ipmiPrintAndRegister(
2141 netfnIntcOEMGeneral,
2142 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
2143 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
2144 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2145 static_cast<ipmi_cmd_t>(
2146 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
2147 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
2148 ipmiPrintAndRegister(
2149 netfnIntcOEMGeneral,
2150 static_cast<ipmi_cmd_t>(
2151 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
2152 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08002153
2154 ipmi::registerHandler(
2155 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2156 static_cast<ipmi::Cmd>(
2157 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
2158 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
2159
Jason M. Bills64796042018-10-03 16:51:55 -07002160 ipmiPrintAndRegister(
2161 netfnIntcOEMGeneral,
2162 static_cast<ipmi_cmd_t>(
2163 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
2164 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
2165 ipmiPrintAndRegister(
2166 netfnIntcOEMGeneral,
2167 static_cast<ipmi_cmd_t>(
2168 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
2169 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05302170
2171 ipmi::registerHandler(
2172 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2173 static_cast<ipmi::Cmd>(
2174 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
2175 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
2176
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05302177 ipmi::registerHandler(
2178 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2179 static_cast<ipmi::Cmd>(
2180 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
2181 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
2182
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002183 // <Get Processor Error Config>
2184 ipmi::registerHandler(
2185 ipmi::prioOemBase, netfnIntcOEMGeneral,
2186 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07002187 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002188 ipmi::Privilege::User, ipmiOEMGetProcessorErrConfig);
2189 // <Set Processor Error Config>
2190 ipmi::registerHandler(
2191 ipmi::prioOemBase, netfnIntcOEMGeneral,
2192 static_cast<ipmi::Cmd>(
Jason M. Bills64796042018-10-03 16:51:55 -07002193 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
Jason M. Bills42bd9c82019-06-28 16:39:34 -07002194 ipmi::Privilege::Admin, ipmiOEMSetProcessorErrConfig);
2195
Yong Li703922d2018-11-06 13:25:31 +08002196 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2197 static_cast<ipmi_cmd_t>(
2198 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
2199 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
2200 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2201 static_cast<ipmi_cmd_t>(
2202 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
2203 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08002204
2205 ipmiPrintAndRegister(
2206 netfnIntcOEMGeneral,
2207 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
2208 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
2209
James Feist5b693632019-07-09 09:06:09 -07002210 ipmi::registerHandler(
2211 ipmi::prioOemBase, netfnIntcOEMGeneral,
2212 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
2213 ipmi::Privilege::User, ipmiOEMGetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08002214
James Feistacc8a4e2019-04-02 14:23:57 -07002215 ipmi::registerHandler(
2216 ipmi::prioOemBase, netfnIntcOEMGeneral,
2217 static_cast<ipmi::Cmd>(
2218 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
2219 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07002220
James Feistacc8a4e2019-04-02 14:23:57 -07002221 ipmi::registerHandler(
2222 ipmi::prioOemBase, netfnIntcOEMGeneral,
2223 static_cast<ipmi::Cmd>(
2224 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
2225 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
2226
2227 ipmi::registerHandler(
2228 ipmi::prioOemBase, netfnIntcOEMGeneral,
2229 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
2230 ipmi::Privilege::User, ipmiOEMSetFscParameter);
2231
2232 ipmi::registerHandler(
2233 ipmi::prioOemBase, netfnIntcOEMGeneral,
2234 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
2235 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07002236
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302237 ipmi::registerHandler(
2238 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
2239 static_cast<ipmi::Cmd>(
2240 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId),
2241 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId);
2242
Chen Yugang39736d52019-07-12 16:24:33 +08002243 ipmi::registerHandler(
2244 ipmi::prioOemBase, netfnIntcOEMGeneral,
2245 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetNmiStatus),
2246 ipmi::Privilege::User, ipmiOEMGetNmiSource);
2247
2248 ipmi::registerHandler(
2249 ipmi::prioOemBase, netfnIntcOEMGeneral,
2250 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus),
2251 ipmi::Privilege::Operator, ipmiOEMSetNmiSource);
2252
Kuiying Wang45f04982018-12-26 09:23:08 +08002253 ipmiPrintAndRegister(
2254 netfnIntcOEMGeneral,
2255 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
2256 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08002257 ipmiPrintAndRegister(
2258 netfnIntcOEMPlatform,
2259 static_cast<ipmi_cmd_t>(
2260 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
2261 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002262 ipmi::registerHandler(
2263 ipmi::prioOemBase, netfnIntcOEMGeneral,
2264 static_cast<ipmi::Cmd>(
2265 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication),
2266 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002267
2268 registerHandler(prioOemBase, netfn::intel::oemGeneral,
2269 netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
2270 ipmiRestoreConfiguration);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002271}
2272
2273} // namespace ipmi