blob: 8a7b443e59c715e1a4bb53dacad723eb024566f4 [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
483ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
484 ipmi_request_t request,
485 ipmi_response_t response,
486 ipmi_data_len_t dataLen,
487 ipmi_context_t context)
488{
489 GetProcessorErrConfigRes* resp =
490 reinterpret_cast<GetProcessorErrConfigRes*>(response);
491
492 if (*dataLen != 0)
493 {
494 *dataLen = 0;
495 return IPMI_CC_REQ_DATA_LEN_INVALID;
496 }
497
Vernon Mauery15419dd2019-05-24 09:40:30 -0700498 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700499 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700500 getService(*dbus, processorErrConfigIntf, processorErrConfigObjPath);
501 Value variant = getDbusProperty(*dbus, service, processorErrConfigObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700502 processorErrConfigIntf, "ResetCfg");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700503 resp->resetCfg = std::get<uint8_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700504
505 std::vector<uint8_t> caterrStatus;
Kuiying Wangbc546672018-11-23 15:41:05 +0800506 sdbusplus::message::variant<std::vector<uint8_t>> message;
Jason M. Bills64796042018-10-03 16:51:55 -0700507
508 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700509 dbus->new_method_call(service.c_str(), processorErrConfigObjPath,
510 "org.freedesktop.DBus.Properties", "Get");
Jason M. Bills64796042018-10-03 16:51:55 -0700511
512 method.append(processorErrConfigIntf, "CATERRStatus");
Vernon Mauery15419dd2019-05-24 09:40:30 -0700513 auto reply = dbus->call(method);
Jason M. Bills64796042018-10-03 16:51:55 -0700514
515 try
516 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800517 reply.read(message);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700518 caterrStatus = std::get<std::vector<uint8_t>>(message);
Jason M. Bills64796042018-10-03 16:51:55 -0700519 }
520 catch (sdbusplus::exception_t&)
521 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800522 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills64796042018-10-03 16:51:55 -0700523 "ipmiOEMGetProcessorErrConfig: error on dbus",
524 phosphor::logging::entry("PRORPERTY=CATERRStatus"),
525 phosphor::logging::entry("PATH=%s", processorErrConfigObjPath),
526 phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf));
527 return IPMI_CC_UNSPECIFIED_ERROR;
528 }
529
530 size_t len =
531 maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size();
532 caterrStatus.resize(len);
533 std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus);
534 *dataLen = sizeof(GetProcessorErrConfigRes);
535
536 return IPMI_CC_OK;
537}
538
539ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
540 ipmi_request_t request,
541 ipmi_response_t response,
542 ipmi_data_len_t dataLen,
543 ipmi_context_t context)
544{
545 SetProcessorErrConfigReq* req =
546 reinterpret_cast<SetProcessorErrConfigReq*>(request);
547
548 if (*dataLen != sizeof(SetProcessorErrConfigReq))
549 {
550 *dataLen = 0;
551 return IPMI_CC_REQ_DATA_LEN_INVALID;
552 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700553 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700554 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700555 getService(*dbus, processorErrConfigIntf, processorErrConfigObjPath);
556 setDbusProperty(*dbus, service, processorErrConfigObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700557 processorErrConfigIntf, "ResetCfg", req->resetCfg);
558
Vernon Mauery15419dd2019-05-24 09:40:30 -0700559 setDbusProperty(*dbus, service, processorErrConfigObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700560 processorErrConfigIntf, "ResetErrorOccurrenceCounts",
561 req->resetErrorOccurrenceCounts);
562 *dataLen = 0;
563
564 return IPMI_CC_OK;
565}
566
Yong Li703922d2018-11-06 13:25:31 +0800567ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
568 ipmi_request_t request,
569 ipmi_response_t response,
570 ipmi_data_len_t dataLen,
571 ipmi_context_t context)
572{
573 GetOEMShutdownPolicyRes* resp =
574 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
575
576 if (*dataLen != 0)
577 {
578 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800579 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800580 *dataLen = 0;
581 return IPMI_CC_REQ_DATA_LEN_INVALID;
582 }
583
584 *dataLen = 0;
585
586 try
587 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700588 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800589 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700590 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
591 Value variant = getDbusProperty(
592 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
593 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800594
595 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
596 convertPolicyFromString(std::get<std::string>(variant)) ==
597 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
598 NoShutdownOnOCOT)
599 {
600 resp->policy = 0;
601 }
602 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
603 convertPolicyFromString(std::get<std::string>(variant)) ==
604 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
605 Policy::ShutdownOnOCOT)
606 {
607 resp->policy = 1;
608 }
609 else
610 {
611 phosphor::logging::log<phosphor::logging::level::ERR>(
612 "oem_set_shutdown_policy: invalid property!",
613 phosphor::logging::entry(
614 "PROP=%s", std::get<std::string>(variant).c_str()));
615 return IPMI_CC_UNSPECIFIED_ERROR;
616 }
Yong Li703922d2018-11-06 13:25:31 +0800617 // TODO needs to check if it is multi-node products,
618 // policy is only supported on node 3/4
619 resp->policySupport = shutdownPolicySupported;
620 }
621 catch (sdbusplus::exception_t& e)
622 {
623 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
624 return IPMI_CC_UNSPECIFIED_ERROR;
625 }
626
627 *dataLen = sizeof(GetOEMShutdownPolicyRes);
628 return IPMI_CC_OK;
629}
630
631ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
632 ipmi_request_t request,
633 ipmi_response_t response,
634 ipmi_data_len_t dataLen,
635 ipmi_context_t context)
636{
637 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800638 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
639 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
640 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800641
642 // TODO needs to check if it is multi-node products,
643 // policy is only supported on node 3/4
644 if (*dataLen != 1)
645 {
646 phosphor::logging::log<phosphor::logging::level::ERR>(
647 "oem_set_shutdown_policy: invalid input len!");
648 *dataLen = 0;
649 return IPMI_CC_REQ_DATA_LEN_INVALID;
650 }
651
652 *dataLen = 0;
653 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
654 {
655 phosphor::logging::log<phosphor::logging::level::ERR>(
656 "oem_set_shutdown_policy: invalid input!");
657 return IPMI_CC_INVALID_FIELD_REQUEST;
658 }
659
Yong Li0669d192019-05-06 14:01:46 +0800660 if (*req == noShutdownOnOCOT)
661 {
662 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
663 Policy::NoShutdownOnOCOT;
664 }
665 else
666 {
667 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
668 Policy::ShutdownOnOCOT;
669 }
670
Yong Li703922d2018-11-06 13:25:31 +0800671 try
672 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700673 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800674 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700675 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800676 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700677 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800678 oemShutdownPolicyObjPathProp,
679 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800680 }
681 catch (sdbusplus::exception_t& e)
682 {
683 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
684 return IPMI_CC_UNSPECIFIED_ERROR;
685 }
686
687 return IPMI_CC_OK;
688}
689
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530690/** @brief implementation for check the DHCP or not in IPv4
691 * @param[in] Channel - Channel number
692 * @returns true or false.
693 */
694static bool isDHCPEnabled(uint8_t Channel)
695{
696 try
697 {
698 auto ethdevice = getChannelName(Channel);
699 if (ethdevice.empty())
700 {
701 return false;
702 }
703 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700704 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530705 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700706 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
707 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530708 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700709 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530710 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
711 {
712 return true;
713 }
714 else
715 {
716 return false;
717 }
718 }
719 catch (sdbusplus::exception_t& e)
720 {
721 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
722 return true;
723 }
724}
725
726/** @brief implementes for check the DHCP or not in IPv6
727 * @param[in] Channel - Channel number
728 * @returns true or false.
729 */
730static bool isDHCPIPv6Enabled(uint8_t Channel)
731{
732
733 try
734 {
735 auto ethdevice = getChannelName(Channel);
736 if (ethdevice.empty())
737 {
738 return false;
739 }
740 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700741 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530742 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700743 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
744 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530745 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700746 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530747 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
748 {
749 return true;
750 }
751 else
752 {
753 return false;
754 }
755 }
756 catch (sdbusplus::exception_t& e)
757 {
758 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
759 return true;
760 }
761}
762
763/** @brief implementes the creating of default new user
764 * @param[in] userName - new username in 16 bytes.
765 * @param[in] userPassword - new password in 20 bytes
766 * @returns ipmi completion code.
767 */
768ipmi::RspType<> ipmiOEMSetUser2Activation(
769 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
770 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
771{
772 bool userState = false;
773 // Check for System Interface not exist and LAN should be static
774 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
775 {
776 ChannelInfo chInfo;
777 try
778 {
779 getChannelInfo(channel, chInfo);
780 }
781 catch (sdbusplus::exception_t& e)
782 {
783 phosphor::logging::log<phosphor::logging::level::ERR>(
784 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
785 phosphor::logging::entry("MSG: %s", e.description()));
786 return ipmi::response(ipmi::ccUnspecifiedError);
787 }
788 if (chInfo.mediumType ==
789 static_cast<uint8_t>(EChannelMediumType::systemInterface))
790 {
791 phosphor::logging::log<phosphor::logging::level::ERR>(
792 "ipmiOEMSetUser2Activation: system interface exist .");
793 return ipmi::response(ipmi::ccCommandNotAvailable);
794 }
795 else
796 {
797
798 if (chInfo.mediumType ==
799 static_cast<uint8_t>(EChannelMediumType::lan8032))
800 {
801 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
802 {
803 phosphor::logging::log<phosphor::logging::level::ERR>(
804 "ipmiOEMSetUser2Activation: DHCP enabled .");
805 return ipmi::response(ipmi::ccCommandNotAvailable);
806 }
807 }
808 }
809 }
810 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
811 if (ipmi::ccSuccess ==
812 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
813 {
814 if (enabledUsers > 1)
815 {
816 phosphor::logging::log<phosphor::logging::level::ERR>(
817 "ipmiOEMSetUser2Activation: more than one user is enabled.");
818 return ipmi::response(ipmi::ccCommandNotAvailable);
819 }
820 // Check the user 2 is enabled or not
821 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
822 if (userState == true)
823 {
824 phosphor::logging::log<phosphor::logging::level::ERR>(
825 "ipmiOEMSetUser2Activation: user 2 already enabled .");
826 return ipmi::response(ipmi::ccCommandNotAvailable);
827 }
828 }
829 else
830 {
831 return ipmi::response(ipmi::ccUnspecifiedError);
832 }
833
834#if BYTE_ORDER == LITTLE_ENDIAN
835 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
836#endif
837#if BYTE_ORDER == BIG_ENDIAN
838 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
839#endif
840
841 if (ipmi::ccSuccess ==
842 ipmiUserSetUserName(ipmiDefaultUserId,
843 reinterpret_cast<const char*>(userName.data())))
844 {
845 if (ipmi::ccSuccess ==
846 ipmiUserSetUserPassword(
847 ipmiDefaultUserId,
848 reinterpret_cast<const char*>(userPassword.data())))
849 {
850 if (ipmi::ccSuccess ==
851 ipmiUserSetPrivilegeAccess(
852 ipmiDefaultUserId,
853 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
854 privAccess, true))
855 {
856 phosphor::logging::log<phosphor::logging::level::INFO>(
857 "ipmiOEMSetUser2Activation: user created successfully ");
858 return ipmi::responseSuccess();
859 }
860 }
861 // we need to delete the default user id which added in this command as
862 // password / priv setting is failed.
863 ipmiUserSetUserName(ipmiDefaultUserId, "");
864 phosphor::logging::log<phosphor::logging::level::ERR>(
865 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
866 }
867 else
868 {
869 phosphor::logging::log<phosphor::logging::level::ERR>(
870 "ipmiOEMSetUser2Activation: Setting username failed.");
871 }
872
873 return ipmi::response(ipmi::ccCommandNotAvailable);
874}
875
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +0530876/** @brief implementes setting password for special user
877 * @param[in] specialUserIndex
878 * @param[in] userPassword - new password in 20 bytes
879 * @returns ipmi completion code.
880 */
881ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
882 uint8_t specialUserIndex,
883 std::vector<uint8_t> userPassword)
884{
885 ChannelInfo chInfo;
886 try
887 {
888 getChannelInfo(ctx->channel, chInfo);
889 }
890 catch (sdbusplus::exception_t& e)
891 {
892 phosphor::logging::log<phosphor::logging::level::ERR>(
893 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
894 phosphor::logging::entry("MSG: %s", e.description()));
895 return ipmi::responseUnspecifiedError();
896 }
897 if (chInfo.mediumType !=
898 static_cast<uint8_t>(EChannelMediumType::systemInterface))
899 {
900 phosphor::logging::log<phosphor::logging::level::ERR>(
901 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
902 "interface");
903 return ipmi::responseCommandNotAvailable();
904 }
905 if (specialUserIndex != 0)
906 {
907 phosphor::logging::log<phosphor::logging::level::ERR>(
908 "ipmiOEMSetSpecialUserPassword: Invalid user account");
909 return ipmi::responseParmOutOfRange();
910 }
911 constexpr uint8_t minPasswordSizeRequired = 6;
912 if (userPassword.size() < minPasswordSizeRequired ||
913 userPassword.size() > ipmi::maxIpmi20PasswordSize)
914 {
915 return ipmi::responseReqDataLenInvalid();
916 }
917 std::string passwd;
918 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
919 userPassword.size());
920 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
921}
922
Kuiying Wang45f04982018-12-26 09:23:08 +0800923namespace ledAction
924{
925using namespace sdbusplus::xyz::openbmc_project::Led::server;
926std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
927 {Physical::Action::Off, 0x00},
928 {Physical::Action::On, 0x10},
929 {Physical::Action::Blink, 0x01}};
930
931std::map<uint8_t, std::string> offsetObjPath = {
932 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
933
934} // namespace ledAction
935
936int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
937 const std::string& objPath, uint8_t& state)
938{
939 try
940 {
941 std::string service = getService(bus, intf, objPath);
942 Value stateValue =
943 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700944 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +0800945 state = ledAction::actionDbusToIpmi.at(
946 sdbusplus::xyz::openbmc_project::Led::server::Physical::
947 convertActionFromString(strState));
948 }
949 catch (sdbusplus::exception::SdBusError& e)
950 {
951 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
952 return -1;
953 }
954 return 0;
955}
956
957ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
958 ipmi_request_t request, ipmi_response_t response,
959 ipmi_data_len_t dataLen, ipmi_context_t context)
960{
961 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
962 // LED Status
963 //[1:0] = Reserved
964 //[3:2] = Status(Amber)
965 //[5:4] = Status(Green)
966 //[7:6] = System Identify
967 // Status definitions:
968 // 00b = Off
969 // 01b = Blink
970 // 10b = On
971 // 11b = invalid
972 if (*dataLen != 0)
973 {
974 phosphor::logging::log<phosphor::logging::level::ERR>(
975 "oem_get_led_status: invalid input len!");
976 *dataLen = 0;
977 return IPMI_CC_REQ_DATA_LEN_INVALID;
978 }
979
980 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
981 *resp = 0;
982 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700983 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +0800984 for (auto it = ledAction::offsetObjPath.begin();
985 it != ledAction::offsetObjPath.end(); ++it)
986 {
987 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700988 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +0800989 {
990 phosphor::logging::log<phosphor::logging::level::ERR>(
991 "oem_get_led_status: fail to get ID LED status!");
992 return IPMI_CC_UNSPECIFIED_ERROR;
993 }
994 *resp |= state << it->first;
995 }
996
997 *dataLen = sizeof(*resp);
998 return IPMI_CC_OK;
999}
1000
Yong Li23737fe2019-02-19 08:49:55 +08001001ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1002 ipmi_request_t request,
1003 ipmi_response_t response,
1004 ipmi_data_len_t dataLen,
1005 ipmi_context_t context)
1006{
1007 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
1008 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
1009
1010 if (*dataLen == 0)
1011 {
1012 phosphor::logging::log<phosphor::logging::level::ERR>(
1013 "CfgHostSerial: invalid input len!",
1014 phosphor::logging::entry("LEN=%d", *dataLen));
1015 return IPMI_CC_REQ_DATA_LEN_INVALID;
1016 }
1017
1018 switch (req->command)
1019 {
1020 case getHostSerialCfgCmd:
1021 {
1022 if (*dataLen != 1)
1023 {
1024 phosphor::logging::log<phosphor::logging::level::ERR>(
1025 "CfgHostSerial: invalid input len!");
1026 *dataLen = 0;
1027 return IPMI_CC_REQ_DATA_LEN_INVALID;
1028 }
1029
1030 *dataLen = 0;
1031
1032 boost::process::ipstream is;
1033 std::vector<std::string> data;
1034 std::string line;
1035 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1036 boost::process::std_out > is);
1037
1038 while (c1.running() && std::getline(is, line) && !line.empty())
1039 {
1040 data.push_back(line);
1041 }
1042
1043 c1.wait();
1044 if (c1.exit_code())
1045 {
1046 phosphor::logging::log<phosphor::logging::level::ERR>(
1047 "CfgHostSerial:: error on execute",
1048 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1049 // Using the default value
1050 *resp = 0;
1051 }
1052 else
1053 {
1054 if (data.size() != 1)
1055 {
1056 phosphor::logging::log<phosphor::logging::level::ERR>(
1057 "CfgHostSerial:: error on read env");
1058 return IPMI_CC_UNSPECIFIED_ERROR;
1059 }
1060 try
1061 {
1062 unsigned long tmp = std::stoul(data[0]);
1063 if (tmp > std::numeric_limits<uint8_t>::max())
1064 {
1065 throw std::out_of_range("Out of range");
1066 }
1067 *resp = static_cast<uint8_t>(tmp);
1068 }
1069 catch (const std::invalid_argument& e)
1070 {
1071 phosphor::logging::log<phosphor::logging::level::ERR>(
1072 "invalid config ",
1073 phosphor::logging::entry("ERR=%s", e.what()));
1074 return IPMI_CC_UNSPECIFIED_ERROR;
1075 }
1076 catch (const std::out_of_range& e)
1077 {
1078 phosphor::logging::log<phosphor::logging::level::ERR>(
1079 "out_of_range config ",
1080 phosphor::logging::entry("ERR=%s", e.what()));
1081 return IPMI_CC_UNSPECIFIED_ERROR;
1082 }
1083 }
1084
1085 *dataLen = 1;
1086 break;
1087 }
1088 case setHostSerialCfgCmd:
1089 {
1090 if (*dataLen != sizeof(CfgHostSerialReq))
1091 {
1092 phosphor::logging::log<phosphor::logging::level::ERR>(
1093 "CfgHostSerial: invalid input len!");
1094 *dataLen = 0;
1095 return IPMI_CC_REQ_DATA_LEN_INVALID;
1096 }
1097
1098 *dataLen = 0;
1099
1100 if (req->parameter > HostSerialCfgParamMax)
1101 {
1102 phosphor::logging::log<phosphor::logging::level::ERR>(
1103 "CfgHostSerial: invalid input!");
1104 return IPMI_CC_INVALID_FIELD_REQUEST;
1105 }
1106
1107 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1108 std::to_string(req->parameter));
1109
1110 c1.wait();
1111 if (c1.exit_code())
1112 {
1113 phosphor::logging::log<phosphor::logging::level::ERR>(
1114 "CfgHostSerial:: error on execute",
1115 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1116 return IPMI_CC_UNSPECIFIED_ERROR;
1117 }
1118 break;
1119 }
1120 default:
1121 phosphor::logging::log<phosphor::logging::level::ERR>(
1122 "CfgHostSerial: invalid input!");
1123 *dataLen = 0;
1124 return IPMI_CC_INVALID_FIELD_REQUEST;
1125 }
1126
1127 return IPMI_CC_OK;
1128}
1129
James Feist91244a62019-02-19 15:04:54 -08001130constexpr const char* thermalModeInterface =
1131 "xyz.openbmc_project.Control.ThermalMode";
1132constexpr const char* thermalModePath =
1133 "/xyz/openbmc_project/control/thermal_mode";
1134
1135bool getFanProfileInterface(
1136 sdbusplus::bus::bus& bus,
1137 boost::container::flat_map<
1138 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1139{
1140 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1141 "GetAll");
1142 call.append(thermalModeInterface);
1143 try
1144 {
1145 auto data = bus.call(call);
1146 data.read(resp);
1147 }
1148 catch (sdbusplus::exception_t& e)
1149 {
1150 phosphor::logging::log<phosphor::logging::level::ERR>(
1151 "getFanProfileInterface: can't get thermal mode!",
1152 phosphor::logging::entry("ERR=%s", e.what()));
1153 return false;
1154 }
1155 return true;
1156}
1157
1158ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1159 ipmi_request_t request, ipmi_response_t response,
1160 ipmi_data_len_t dataLen, ipmi_context_t context)
1161{
1162
1163 if (*dataLen < 2 || *dataLen > 7)
1164 {
1165 phosphor::logging::log<phosphor::logging::level::ERR>(
1166 "ipmiOEMSetFanConfig: invalid input len!");
1167 *dataLen = 0;
1168 return IPMI_CC_REQ_DATA_LEN_INVALID;
1169 }
1170
1171 // todo: tell bios to only send first 2 bytes
1172
1173 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1174 boost::container::flat_map<
1175 std::string, std::variant<std::vector<std::string>, std::string>>
1176 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001177 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1178 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001179 {
1180 return IPMI_CC_UNSPECIFIED_ERROR;
1181 }
1182
1183 std::vector<std::string>* supported =
1184 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1185 if (supported == nullptr)
1186 {
1187 return IPMI_CC_INVALID_FIELD_REQUEST;
1188 }
1189 std::string mode;
1190 if (req->flags &
1191 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1192 {
1193 bool performanceMode =
1194 (req->flags & (1 << static_cast<uint8_t>(
1195 setFanProfileFlags::performAcousSelect))) > 0;
1196
1197 if (performanceMode)
1198 {
1199
1200 if (std::find(supported->begin(), supported->end(),
1201 "Performance") != supported->end())
1202 {
1203 mode = "Performance";
1204 }
1205 }
1206 else
1207 {
1208
1209 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1210 supported->end())
1211 {
1212 mode = "Acoustic";
1213 }
1214 }
1215 if (mode.empty())
1216 {
1217 return IPMI_CC_INVALID_FIELD_REQUEST;
1218 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001219 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001220 thermalModeInterface, "Current", mode);
1221 }
1222
1223 return IPMI_CC_OK;
1224}
1225
James Feist5b693632019-07-09 09:06:09 -07001226ipmi::RspType<uint8_t, // profile support map
1227 uint8_t, // fan control profile enable
1228 uint8_t, // flags
1229 uint32_t // dimm presence bit map
1230 >
1231 ipmiOEMGetFanConfig(uint8_t dimmGroupId)
James Feist91244a62019-02-19 15:04:54 -08001232{
James Feist91244a62019-02-19 15:04:54 -08001233 boost::container::flat_map<
1234 std::string, std::variant<std::vector<std::string>, std::string>>
1235 profileData;
1236
Vernon Mauery15419dd2019-05-24 09:40:30 -07001237 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1238 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001239 {
James Feist5b693632019-07-09 09:06:09 -07001240 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001241 }
1242
1243 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1244
1245 if (current == nullptr)
1246 {
1247 phosphor::logging::log<phosphor::logging::level::ERR>(
1248 "ipmiOEMGetFanConfig: can't get current mode!");
James Feist5b693632019-07-09 09:06:09 -07001249 return ipmi::responseResponseError();
James Feist91244a62019-02-19 15:04:54 -08001250 }
1251 bool performance = (*current == "Performance");
1252
James Feist5b693632019-07-09 09:06:09 -07001253 uint8_t flags = 0;
James Feist91244a62019-02-19 15:04:54 -08001254 if (performance)
1255 {
James Feist5b693632019-07-09 09:06:09 -07001256 flags |= 1 << 2;
James Feist91244a62019-02-19 15:04:54 -08001257 }
1258
James Feist5b693632019-07-09 09:06:09 -07001259 return ipmi::responseSuccess(0, 0, flags, 0);
James Feist91244a62019-02-19 15:04:54 -08001260}
James Feist5f957ca2019-03-14 15:33:55 -07001261constexpr const char* cfmLimitSettingPath =
1262 "/xyz/openbmc_project/control/cfm_limit";
1263constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001264constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feistacc8a4e2019-04-02 14:23:57 -07001265constexpr const char* pidConfigurationIface =
1266 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001267
1268static std::string getExitAirConfigPath()
1269{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001270 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001271 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001272 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1273 "/xyz/openbmc_project/object_mapper",
1274 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001275
James Feistacc8a4e2019-04-02 14:23:57 -07001276 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001277 std::string path;
1278 GetSubTreeType resp;
1279 try
1280 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001281 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001282 reply.read(resp);
1283 }
1284 catch (sdbusplus::exception_t&)
1285 {
1286 phosphor::logging::log<phosphor::logging::level::ERR>(
1287 "ipmiOEMGetFscParameter: mapper error");
1288 };
1289 auto config = std::find_if(resp.begin(), resp.end(), [](const auto& pair) {
1290 return pair.first.find("Exit_Air") != std::string::npos;
1291 });
1292 if (config != resp.end())
1293 {
1294 path = std::move(config->first);
1295 }
1296 return path;
1297}
James Feist5f957ca2019-03-14 15:33:55 -07001298
James Feistacc8a4e2019-04-02 14:23:57 -07001299// flat map to make alphabetical
1300static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1301{
1302 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001303 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001304 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001305 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1306 "/xyz/openbmc_project/object_mapper",
1307 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001308
1309 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1310 GetSubTreeType resp;
1311
1312 try
1313 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001314 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001315 reply.read(resp);
1316 }
1317 catch (sdbusplus::exception_t&)
1318 {
1319 phosphor::logging::log<phosphor::logging::level::ERR>(
1320 "getFanConfigPaths: mapper error");
1321 };
1322 for (const auto& [path, objects] : resp)
1323 {
1324 if (objects.empty())
1325 {
1326 continue; // should be impossible
1327 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001328
1329 try
1330 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001331 ret.emplace(path,
1332 getAllDbusProperties(*dbus, objects[0].first, path,
1333 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001334 }
1335 catch (sdbusplus::exception_t& e)
1336 {
1337 phosphor::logging::log<phosphor::logging::level::ERR>(
1338 "getPidConfigs: can't get DbusProperties!",
1339 phosphor::logging::entry("ERR=%s", e.what()));
1340 }
James Feistacc8a4e2019-04-02 14:23:57 -07001341 }
1342 return ret;
1343}
1344
1345ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1346{
1347 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1348 if (data.empty())
1349 {
1350 return ipmi::responseResponseError();
1351 }
1352 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1353 for (const auto& [_, pid] : data)
1354 {
1355 auto findClass = pid.find("Class");
1356 if (findClass == pid.end())
1357 {
1358 phosphor::logging::log<phosphor::logging::level::ERR>(
1359 "ipmiOEMGetFscParameter: found illegal pid "
1360 "configurations");
1361 return ipmi::responseResponseError();
1362 }
1363 std::string type = std::get<std::string>(findClass->second);
1364 if (type == "fan")
1365 {
1366 auto findOutLimit = pid.find("OutLimitMin");
1367 if (findOutLimit == pid.end())
1368 {
1369 phosphor::logging::log<phosphor::logging::level::ERR>(
1370 "ipmiOEMGetFscParameter: found illegal pid "
1371 "configurations");
1372 return ipmi::responseResponseError();
1373 }
1374 // get the min out of all the offsets
1375 minOffset = std::min(
1376 minOffset,
1377 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1378 }
1379 }
1380 if (minOffset == std::numeric_limits<uint8_t>::max())
1381 {
1382 phosphor::logging::log<phosphor::logging::level::ERR>(
1383 "ipmiOEMGetFscParameter: found no fan configurations!");
1384 return ipmi::responseResponseError();
1385 }
1386
1387 return ipmi::responseSuccess(minOffset);
1388}
1389
1390ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1391{
1392 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1393 if (data.empty())
1394 {
1395
1396 phosphor::logging::log<phosphor::logging::level::ERR>(
1397 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1398 return ipmi::responseResponseError();
1399 }
1400
Vernon Mauery15419dd2019-05-24 09:40:30 -07001401 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001402 bool found = false;
1403 for (const auto& [path, pid] : data)
1404 {
1405 auto findClass = pid.find("Class");
1406 if (findClass == pid.end())
1407 {
1408
1409 phosphor::logging::log<phosphor::logging::level::ERR>(
1410 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1411 "configurations");
1412 return ipmi::responseResponseError();
1413 }
1414 std::string type = std::get<std::string>(findClass->second);
1415 if (type == "fan")
1416 {
1417 auto findOutLimit = pid.find("OutLimitMin");
1418 if (findOutLimit == pid.end())
1419 {
1420
1421 phosphor::logging::log<phosphor::logging::level::ERR>(
1422 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1423 "configurations");
1424 return ipmi::responseResponseError();
1425 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001426 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001427 path, pidConfigurationIface, "OutLimitMin",
1428 static_cast<double>(offset));
1429 found = true;
1430 }
1431 }
1432 if (!found)
1433 {
1434 phosphor::logging::log<phosphor::logging::level::ERR>(
1435 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1436 return ipmi::responseResponseError();
1437 }
1438
1439 return ipmi::responseSuccess();
1440}
1441
1442ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1443 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001444{
1445 constexpr const size_t disableLimiting = 0x0;
1446
Vernon Mauery15419dd2019-05-24 09:40:30 -07001447 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001448 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001449 {
James Feistacc8a4e2019-04-02 14:23:57 -07001450 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001451 {
James Feistfaa4f222019-03-21 16:21:55 -07001452 std::string path = getExitAirConfigPath();
Vernon Mauery15419dd2019-05-24 09:40:30 -07001453 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001454 path, pidConfigurationIface, "SetPoint",
1455 static_cast<double>(param2));
1456 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001457 }
1458 else
1459 {
James Feistacc8a4e2019-04-02 14:23:57 -07001460 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001461 }
1462 }
James Feistacc8a4e2019-04-02 14:23:57 -07001463 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001464 {
James Feistacc8a4e2019-04-02 14:23:57 -07001465 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001466
1467 // must be greater than 50 based on eps
1468 if (cfm < 50 && cfm != disableLimiting)
1469 {
James Feistacc8a4e2019-04-02 14:23:57 -07001470 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001471 }
1472
1473 try
1474 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001475 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001476 cfmLimitIface, "Limit",
1477 static_cast<double>(cfm));
1478 }
1479 catch (sdbusplus::exception_t& e)
1480 {
1481 phosphor::logging::log<phosphor::logging::level::ERR>(
1482 "ipmiOEMSetFscParameter: can't set cfm setting!",
1483 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001484 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001485 }
James Feistacc8a4e2019-04-02 14:23:57 -07001486 return ipmi::responseSuccess();
1487 }
1488 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1489 {
1490 constexpr const size_t maxDomainCount = 8;
1491 uint8_t requestedDomainMask = param1;
1492 boost::container::flat_map data = getPidConfigs();
1493 if (data.empty())
1494 {
1495
1496 phosphor::logging::log<phosphor::logging::level::ERR>(
1497 "ipmiOEMSetFscParameter: found no pid configurations!");
1498 return ipmi::responseResponseError();
1499 }
1500 size_t count = 0;
1501 for (const auto& [path, pid] : data)
1502 {
1503 auto findClass = pid.find("Class");
1504 if (findClass == pid.end())
1505 {
1506
1507 phosphor::logging::log<phosphor::logging::level::ERR>(
1508 "ipmiOEMSetFscParameter: found illegal pid "
1509 "configurations");
1510 return ipmi::responseResponseError();
1511 }
1512 std::string type = std::get<std::string>(findClass->second);
1513 if (type == "fan")
1514 {
1515 if (requestedDomainMask & (1 << count))
1516 {
1517 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001518 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001519 pidConfigurationIface, "OutLimitMax",
1520 static_cast<double>(param2));
1521 }
1522 count++;
1523 }
1524 }
1525 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001526 }
1527 else
1528 {
1529 // todo other command parts possibly
1530 // tcontrol is handled in peci now
1531 // fan speed offset not implemented yet
1532 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001533 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001534 }
1535}
1536
James Feistacc8a4e2019-04-02 14:23:57 -07001537ipmi::RspType<
1538 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1539 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001540{
James Feistfaa4f222019-03-21 16:21:55 -07001541 constexpr uint8_t legacyDefaultExitAirLimit = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001542
Vernon Mauery15419dd2019-05-24 09:40:30 -07001543 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001544 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001545 {
James Feistacc8a4e2019-04-02 14:23:57 -07001546 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001547 {
James Feistacc8a4e2019-04-02 14:23:57 -07001548 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001549 }
1550
James Feistacc8a4e2019-04-02 14:23:57 -07001551 if (*param != legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001552 {
James Feistacc8a4e2019-04-02 14:23:57 -07001553 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001554 }
1555 uint8_t setpoint = legacyDefaultExitAirLimit;
1556 std::string path = getExitAirConfigPath();
1557 if (path.size())
1558 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001559 Value val = ipmi::getDbusProperty(
1560 *dbus, "xyz.openbmc_project.EntityManager", path,
1561 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001562 setpoint = std::floor(std::get<double>(val) + 0.5);
1563 }
1564
1565 // old implementation used to return the "default" and current, we
1566 // don't make the default readily available so just make both the
1567 // same
James Feistfaa4f222019-03-21 16:21:55 -07001568
James Feistacc8a4e2019-04-02 14:23:57 -07001569 return ipmi::responseSuccess(
1570 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001571 }
James Feistacc8a4e2019-04-02 14:23:57 -07001572 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1573 {
1574 constexpr const size_t maxDomainCount = 8;
1575
1576 if (!param)
1577 {
1578 return ipmi::responseReqDataLenInvalid();
1579 }
1580 uint8_t requestedDomain = *param;
1581 if (requestedDomain >= maxDomainCount)
1582 {
1583 return ipmi::responseInvalidFieldRequest();
1584 }
1585
1586 boost::container::flat_map data = getPidConfigs();
1587 if (data.empty())
1588 {
1589 phosphor::logging::log<phosphor::logging::level::ERR>(
1590 "ipmiOEMGetFscParameter: found no pid configurations!");
1591 return ipmi::responseResponseError();
1592 }
1593 size_t count = 0;
1594 for (const auto& [_, pid] : data)
1595 {
1596 auto findClass = pid.find("Class");
1597 if (findClass == pid.end())
1598 {
1599 phosphor::logging::log<phosphor::logging::level::ERR>(
1600 "ipmiOEMGetFscParameter: found illegal pid "
1601 "configurations");
1602 return ipmi::responseResponseError();
1603 }
1604 std::string type = std::get<std::string>(findClass->second);
1605 if (type == "fan")
1606 {
1607 if (requestedDomain == count)
1608 {
1609 auto findOutLimit = pid.find("OutLimitMax");
1610 if (findOutLimit == pid.end())
1611 {
1612 phosphor::logging::log<phosphor::logging::level::ERR>(
1613 "ipmiOEMGetFscParameter: found illegal pid "
1614 "configurations");
1615 return ipmi::responseResponseError();
1616 }
1617
1618 return ipmi::responseSuccess(
1619 static_cast<uint8_t>(std::floor(
1620 std::get<double>(findOutLimit->second) + 0.5)));
1621 }
1622 else
1623 {
1624 count++;
1625 }
1626 }
1627 }
1628
1629 return ipmi::responseInvalidFieldRequest();
1630 }
1631 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001632 {
1633
1634 /*
1635 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001636 previous behavior didn't seem to prevent this, ignore the check for
1637 now.
James Feist5f957ca2019-03-14 15:33:55 -07001638
James Feistacc8a4e2019-04-02 14:23:57 -07001639 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001640 {
1641 phosphor::logging::log<phosphor::logging::level::ERR>(
1642 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001643 return IPMI_CC_REQ_DATA_LEN_INVALID;
1644 }
1645 */
1646 Value cfmLimit;
1647 Value cfmMaximum;
1648 try
1649 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001650 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001651 cfmLimitSettingPath, cfmLimitIface,
1652 "Limit");
1653 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001654 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001655 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1656 }
1657 catch (sdbusplus::exception_t& e)
1658 {
1659 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001660 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001661 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001662 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001663 }
1664
James Feistacc8a4e2019-04-02 14:23:57 -07001665 double cfmMax = std::get<double>(cfmMaximum);
1666 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001667
James Feistacc8a4e2019-04-02 14:23:57 -07001668 cfmLim = std::floor(cfmLim + 0.5);
1669 cfmMax = std::floor(cfmMax + 0.5);
1670 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1671 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001672
James Feistacc8a4e2019-04-02 14:23:57 -07001673 return ipmi::responseSuccess(
1674 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001675 }
James Feistacc8a4e2019-04-02 14:23:57 -07001676
James Feist5f957ca2019-03-14 15:33:55 -07001677 else
1678 {
1679 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001680 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001681 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001682 }
1683}
1684
Zhu, Yungebe560b02019-04-21 21:19:21 -04001685ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
1686 uint8_t faultState,
1687 uint8_t faultGroup,
1688 std::array<uint8_t, 8>& ledStateData)
1689{
1690 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
1691 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
1692 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
1693 static const std::array<std::string, maxFaultType> faultNames = {
1694 "faultFan", "faultTemp", "faultPower",
1695 "faultDriveSlot", "faultSoftware", "faultMemory"};
1696 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
1697 static constexpr const char* postfixValue = "/value";
1698
1699 constexpr uint8_t maxFaultSource = 0x4;
1700 constexpr uint8_t skipLEDs = 0xFF;
1701 constexpr uint8_t pinSize = 64;
1702 constexpr uint8_t groupSize = 16;
1703
1704 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
1705 uint64_t resFIndex = 0;
1706 std::string resFType;
1707 std::string service;
1708 ObjectValueTree valueTree;
1709
1710 // Validate the source, fault type
1711 if ((sourceId >= maxFaultSource) ||
1712 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
1713 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
1714 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
1715 {
1716 return ipmi::responseParmOutOfRange();
1717 }
1718
Vernon Mauery15419dd2019-05-24 09:40:30 -07001719 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04001720 try
1721 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001722 service = getService(*dbus, intf, objpath);
1723 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04001724 }
1725 catch (const std::exception& e)
1726 {
1727 phosphor::logging::log<phosphor::logging::level::ERR>(
1728 "No object implements interface",
1729 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1730 phosphor::logging::entry("INTF=%s", intf));
1731 return ipmi::responseResponseError();
1732 }
1733
1734 if (valueTree.empty())
1735 {
1736 phosphor::logging::log<phosphor::logging::level::ERR>(
1737 "No object implements interface",
1738 phosphor::logging::entry("INTF=%s", intf));
1739 return ipmi::responseResponseError();
1740 }
1741
1742 for (const auto& item : valueTree)
1743 {
1744 // find LedFault configuration
1745 auto interface =
1746 item.second.find("xyz.openbmc_project.Configuration.LedFault");
1747 if (interface == item.second.end())
1748 {
1749 continue;
1750 }
1751
1752 // find matched fault type: faultMemmory / faultFan
1753 // find LedGpioPins/FaultIndex configuration
1754 auto propertyFaultType = interface->second.find("FaultType");
1755 auto propertyFIndex = interface->second.find("FaultIndex");
1756 auto ledIndex = interface->second.find("LedGpioPins");
1757
1758 if (propertyFaultType == interface->second.end() ||
1759 propertyFIndex == interface->second.end() ||
1760 ledIndex == interface->second.end())
1761 {
1762 continue;
1763 }
1764
1765 try
1766 {
1767 Value valIndex = propertyFIndex->second;
1768 resFIndex = std::get<uint64_t>(valIndex);
1769
1770 Value valFType = propertyFaultType->second;
1771 resFType = std::get<std::string>(valFType);
1772 }
1773 catch (const std::bad_variant_access& e)
1774 {
1775 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1776 return ipmi::responseResponseError();
1777 }
1778 // find the matched requested fault type: faultMemmory or faultFan
1779 if (resFType != faultNames[faultType])
1780 {
1781 continue;
1782 }
1783
1784 // read LedGpioPins data
1785 std::vector<uint64_t> ledgpios;
1786 std::variant<std::vector<uint64_t>> message;
1787
Vernon Mauery15419dd2019-05-24 09:40:30 -07001788 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04001789 service.c_str(), (std::string(item.first)).c_str(),
1790 "org.freedesktop.DBus.Properties", "Get");
1791
1792 method.append("xyz.openbmc_project.Configuration.LedFault",
1793 "LedGpioPins");
1794
1795 try
1796 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001797 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04001798 reply.read(message);
1799 ledgpios = std::get<std::vector<uint64_t>>(message);
1800 }
1801 catch (std::exception& e)
1802 {
1803 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1804 return ipmi::responseResponseError();
1805 }
1806
1807 // Check the size to be sure it will never overflow on groupSize
1808 if (ledgpios.size() > groupSize)
1809 {
1810 phosphor::logging::log<phosphor::logging::level::ERR>(
1811 "Fault gpio Pins out of range!");
1812 return ipmi::responseParmOutOfRange();
1813 }
1814 // Store data, according to command data bit index order
1815 for (int i = 0; i < ledgpios.size(); i++)
1816 {
1817 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
1818 }
1819 }
1820
1821 switch (RemoteFaultType(faultType))
1822 {
1823 case (RemoteFaultType::fan):
1824 case (RemoteFaultType::memory):
1825 {
1826 if (faultGroup == skipLEDs)
1827 {
1828 return ipmi::responseSuccess();
1829 }
1830
1831 uint64_t ledState = 0;
1832 // calculate led state bit filed count, each byte has 8bits
1833 // the maximum bits will be 8 * 8 bits
1834 constexpr uint8_t size = sizeof(ledStateData) * 8;
1835 for (int i = 0; i < sizeof(ledStateData); i++)
1836 {
1837 ledState = (uint64_t)(ledState << 8);
1838 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
1839 }
1840
1841 std::bitset<size> ledStateBits(ledState);
1842 std::string gpioValue;
1843 for (int i = 0; i < size; i++)
1844 { // skip invalid value
1845 if (ledFaultPins[i] == 0xFFFF)
1846 {
1847 continue;
1848 }
1849
1850 std::string device = sysGpioPath +
1851 std::to_string(ledFaultPins[i]) +
1852 postfixValue;
1853 std::fstream gpioFile;
1854
1855 gpioFile.open(device, std::ios::out);
1856
1857 if (!gpioFile.good())
1858 {
1859 phosphor::logging::log<phosphor::logging::level::ERR>(
1860 "Not Find Led Gpio Device!",
1861 phosphor::logging::entry("DEVICE=%s", device.c_str()));
1862 return ipmi::responseResponseError();
1863 }
1864 gpioFile << std::to_string(
1865 static_cast<uint8_t>(ledStateBits[i]));
1866 gpioFile.close();
1867 }
1868 break;
1869 }
1870 default:
1871 {
1872 // now only support two fault types
1873 return ipmi::responseParmOutOfRange();
1874 }
1875 }
1876
1877 return ipmi::responseSuccess();
1878}
1879
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301880ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
1881{
1882 uint8_t prodId = 0;
1883 try
1884 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001885 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301886 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001887 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301888 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
1889 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001890 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301891 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
1892 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
1893 }
1894 catch (std::exception& e)
1895 {
1896 phosphor::logging::log<phosphor::logging::level::ERR>(
1897 "ipmiOEMReadBoardProductId: Product ID read failed!",
1898 phosphor::logging::entry("ERR=%s", e.what()));
1899 }
1900 return ipmi::responseSuccess(prodId);
1901}
1902
Vernon Mauery4ac799d2019-05-20 15:50:37 -07001903ipmi::RspType<uint8_t /* restore status */>
1904 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
1905{
1906 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
1907
1908 if (clr != expClr)
1909 {
1910 return ipmi::responseInvalidFieldRequest();
1911 }
1912 constexpr uint8_t cmdStatus = 0;
1913 constexpr uint8_t cmdDefaultRestore = 0xaa;
1914 constexpr uint8_t cmdFullRestore = 0xbb;
1915 constexpr uint8_t cmdFormat = 0xcc;
1916
1917 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
1918
1919 switch (cmd)
1920 {
1921 case cmdStatus:
1922 break;
1923 case cmdDefaultRestore:
1924 case cmdFullRestore:
1925 case cmdFormat:
1926 {
1927 // write file to rwfs root
1928 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
1929 std::ofstream restoreFile(restoreOpFname);
1930 if (!restoreFile)
1931 {
1932 return ipmi::responseUnspecifiedError();
1933 }
1934 restoreFile << value << "\n";
1935 break;
1936 }
1937 default:
1938 return ipmi::responseInvalidFieldRequest();
1939 }
1940
1941 constexpr uint8_t restorePending = 0;
1942 constexpr uint8_t restoreComplete = 1;
1943
1944 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
1945 ? restorePending
1946 : restoreComplete;
1947 return ipmi::responseSuccess(restoreStatus);
1948}
1949
Chen Yugang39736d52019-07-12 16:24:33 +08001950ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void)
1951{
1952 uint8_t bmcSource;
1953 namespace nmi = sdbusplus::com::intel::Control::server;
1954
1955 try
1956 {
1957 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1958 std::string service =
1959 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
1960 Value variant =
1961 getDbusProperty(*dbus, service, oemNmiSourceObjPath,
1962 oemNmiSourceIntf, oemNmiBmcSourceObjPathProp);
1963
1964 switch (nmi::NMISource::convertBMCSourceSignalFromString(
1965 std::get<std::string>(variant)))
1966 {
1967 case nmi::NMISource::BMCSourceSignal::None:
1968 bmcSource = static_cast<uint8_t>(NmiSource::none);
1969 break;
1970 case nmi::NMISource::BMCSourceSignal::FpBtn:
1971 bmcSource = static_cast<uint8_t>(NmiSource::fpBtn);
1972 break;
1973 case nmi::NMISource::BMCSourceSignal::WdPreTimeout:
1974 bmcSource = static_cast<uint8_t>(NmiSource::wdPreTimeout);
1975 break;
1976 case nmi::NMISource::BMCSourceSignal::PefMatch:
1977 bmcSource = static_cast<uint8_t>(NmiSource::pefMatch);
1978 break;
1979 case nmi::NMISource::BMCSourceSignal::ChassisCmd:
1980 bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd);
1981 break;
1982 case nmi::NMISource::BMCSourceSignal::MemoryError:
1983 bmcSource = static_cast<uint8_t>(NmiSource::memoryError);
1984 break;
1985 case nmi::NMISource::BMCSourceSignal::PciSerrPerr:
1986 bmcSource = static_cast<uint8_t>(NmiSource::pciSerrPerr);
1987 break;
1988 case nmi::NMISource::BMCSourceSignal::SouthbridgeNmi:
1989 bmcSource = static_cast<uint8_t>(NmiSource::southbridgeNmi);
1990 break;
1991 case nmi::NMISource::BMCSourceSignal::ChipsetNmi:
1992 bmcSource = static_cast<uint8_t>(NmiSource::chipsetNmi);
1993 break;
1994 default:
1995 phosphor::logging::log<phosphor::logging::level::ERR>(
1996 "NMI source: invalid property!",
1997 phosphor::logging::entry(
1998 "PROP=%s", std::get<std::string>(variant).c_str()));
1999 return ipmi::responseResponseError();
2000 }
2001 }
2002 catch (sdbusplus::exception::SdBusError& e)
2003 {
2004 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2005 return ipmi::responseResponseError();
2006 }
2007
2008 return ipmi::responseSuccess(bmcSource);
2009}
2010
2011ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId)
2012{
2013 namespace nmi = sdbusplus::com::intel::Control::server;
2014
2015 nmi::NMISource::BMCSourceSignal bmcSourceSignal =
2016 nmi::NMISource::BMCSourceSignal::None;
2017
2018 switch (NmiSource(sourceId))
2019 {
2020 case NmiSource::none:
2021 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None;
2022 break;
2023 case NmiSource::fpBtn:
2024 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FpBtn;
2025 break;
2026 case NmiSource::wdPreTimeout:
2027 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::WdPreTimeout;
2028 break;
2029 case NmiSource::pefMatch:
2030 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PefMatch;
2031 break;
2032 case NmiSource::chassisCmd:
2033 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd;
2034 break;
2035 case NmiSource::memoryError:
2036 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError;
2037 break;
2038 case NmiSource::pciSerrPerr:
2039 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciSerrPerr;
2040 break;
2041 case NmiSource::southbridgeNmi:
2042 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::SouthbridgeNmi;
2043 break;
2044 case NmiSource::chipsetNmi:
2045 bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChipsetNmi;
2046 break;
2047 default:
2048 phosphor::logging::log<phosphor::logging::level::ERR>(
2049 "NMI source: invalid property!");
2050 return ipmi::responseResponseError();
2051 }
2052
2053 try
2054 {
2055 // keep NMI signal source
2056 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
2057 std::string service =
2058 getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath);
2059 setDbusProperty(
2060 *dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf,
2061 oemNmiBmcSourceObjPathProp,
2062 sdbusplus::com::intel::Control::server::convertForMessage(
2063 bmcSourceSignal));
2064 }
2065 catch (sdbusplus::exception_t& e)
2066 {
2067 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
2068 return ipmi::responseResponseError();
2069 }
2070
2071 return ipmi::responseSuccess();
2072}
2073
Jason M. Bills64796042018-10-03 16:51:55 -07002074static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002075{
2076 phosphor::logging::log<phosphor::logging::level::INFO>(
2077 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07002078 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
2079 ipmiOEMWildcard,
2080 PRIVILEGE_USER); // wildcard default handler
2081 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
2082 ipmiOEMWildcard,
2083 PRIVILEGE_USER); // wildcard default handler
2084 ipmiPrintAndRegister(
2085 netfnIntcOEMGeneral,
2086 static_cast<ipmi_cmd_t>(
2087 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
2088 NULL, ipmiOEMGetChassisIdentifier,
2089 PRIVILEGE_USER); // get chassis identifier
2090 ipmiPrintAndRegister(
2091 netfnIntcOEMGeneral,
2092 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
2093 NULL, ipmiOEMSetSystemGUID,
2094 PRIVILEGE_ADMIN); // set system guid
2095 ipmiPrintAndRegister(
2096 netfnIntcOEMGeneral,
2097 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
2098 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
2099 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2100 static_cast<ipmi_cmd_t>(
2101 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
2102 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
2103 ipmiPrintAndRegister(
2104 netfnIntcOEMGeneral,
2105 static_cast<ipmi_cmd_t>(
2106 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
2107 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08002108
2109 ipmi::registerHandler(
2110 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2111 static_cast<ipmi::Cmd>(
2112 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
2113 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
2114
Jason M. Bills64796042018-10-03 16:51:55 -07002115 ipmiPrintAndRegister(
2116 netfnIntcOEMGeneral,
2117 static_cast<ipmi_cmd_t>(
2118 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
2119 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
2120 ipmiPrintAndRegister(
2121 netfnIntcOEMGeneral,
2122 static_cast<ipmi_cmd_t>(
2123 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
2124 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05302125
2126 ipmi::registerHandler(
2127 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2128 static_cast<ipmi::Cmd>(
2129 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
2130 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
2131
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05302132 ipmi::registerHandler(
2133 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2134 static_cast<ipmi::Cmd>(
2135 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
2136 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
2137
Jason M. Bills64796042018-10-03 16:51:55 -07002138 ipmiPrintAndRegister(
2139 netfnIntcOEMGeneral,
2140 static_cast<ipmi_cmd_t>(
2141 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
2142 NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
2143 ipmiPrintAndRegister(
2144 netfnIntcOEMGeneral,
2145 static_cast<ipmi_cmd_t>(
2146 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
2147 NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
Yong Li703922d2018-11-06 13:25:31 +08002148 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2149 static_cast<ipmi_cmd_t>(
2150 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
2151 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
2152 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2153 static_cast<ipmi_cmd_t>(
2154 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
2155 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08002156
2157 ipmiPrintAndRegister(
2158 netfnIntcOEMGeneral,
2159 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
2160 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
2161
James Feist5b693632019-07-09 09:06:09 -07002162 ipmi::registerHandler(
2163 ipmi::prioOemBase, netfnIntcOEMGeneral,
2164 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
2165 ipmi::Privilege::User, ipmiOEMGetFanConfig);
James Feist91244a62019-02-19 15:04:54 -08002166
James Feistacc8a4e2019-04-02 14:23:57 -07002167 ipmi::registerHandler(
2168 ipmi::prioOemBase, netfnIntcOEMGeneral,
2169 static_cast<ipmi::Cmd>(
2170 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
2171 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07002172
James Feistacc8a4e2019-04-02 14:23:57 -07002173 ipmi::registerHandler(
2174 ipmi::prioOemBase, netfnIntcOEMGeneral,
2175 static_cast<ipmi::Cmd>(
2176 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
2177 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
2178
2179 ipmi::registerHandler(
2180 ipmi::prioOemBase, netfnIntcOEMGeneral,
2181 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
2182 ipmi::Privilege::User, ipmiOEMSetFscParameter);
2183
2184 ipmi::registerHandler(
2185 ipmi::prioOemBase, netfnIntcOEMGeneral,
2186 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
2187 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07002188
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302189 ipmi::registerHandler(
2190 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
2191 static_cast<ipmi::Cmd>(
2192 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId),
2193 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId);
2194
Chen Yugang39736d52019-07-12 16:24:33 +08002195 ipmi::registerHandler(
2196 ipmi::prioOemBase, netfnIntcOEMGeneral,
2197 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetNmiStatus),
2198 ipmi::Privilege::User, ipmiOEMGetNmiSource);
2199
2200 ipmi::registerHandler(
2201 ipmi::prioOemBase, netfnIntcOEMGeneral,
2202 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetNmiStatus),
2203 ipmi::Privilege::Operator, ipmiOEMSetNmiSource);
2204
Kuiying Wang45f04982018-12-26 09:23:08 +08002205 ipmiPrintAndRegister(
2206 netfnIntcOEMGeneral,
2207 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
2208 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08002209 ipmiPrintAndRegister(
2210 netfnIntcOEMPlatform,
2211 static_cast<ipmi_cmd_t>(
2212 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
2213 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002214 ipmi::registerHandler(
2215 ipmi::prioOemBase, netfnIntcOEMGeneral,
2216 static_cast<ipmi::Cmd>(
2217 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication),
2218 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002219
2220 registerHandler(prioOemBase, netfn::intel::oemGeneral,
2221 netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
2222 ipmiRestoreConfiguration);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002223}
2224
2225} // namespace ipmi