blob: ea51f916a6a482e59c09aa1b8f80dd3ded70eb4f [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>
Yong Li0669d192019-05-06 14:01:46 +080026#include <com/intel/Control/OCOTShutdownPolicy/server.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070027#include <commandutils.hpp>
Vernon Mauery4ac799d2019-05-20 15:50:37 -070028#include <filesystem>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080029#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080030#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070031#include <ipmid/utils.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080032#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080033#include <phosphor-logging/log.hpp>
34#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053035#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080036#include <string>
James Feist91244a62019-02-19 15:04:54 -080037#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080038#include <vector>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080039
40namespace ipmi
41{
Jason M. Bills64796042018-10-03 16:51:55 -070042static void registerOEMFunctions() __attribute__((constructor));
Vernon Mauery4ac799d2019-05-20 15:50:37 -070043
44namespace netfn::intel
45{
46constexpr NetFn oemGeneral = netFnOemOne;
47constexpr Cmd cmdRestoreConfiguration = 0x02;
48} // namespace netfn::intel
49
Jason M. Bills64796042018-10-03 16:51:55 -070050static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080051
Suryakanth Sekard509eb92018-11-15 17:44:11 +053052static constexpr auto ethernetIntf =
53 "xyz.openbmc_project.Network.EthernetInterface";
54static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
55static constexpr auto networkService = "xyz.openbmc_project.Network";
56static constexpr auto networkRoot = "/xyz/openbmc_project/network";
57
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080058// return code: 0 successful
59int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
60{
61 std::string objpath = "/xyz/openbmc_project/FruDevice";
62 std::string intf = "xyz.openbmc_project.FruDeviceManager";
63 std::string service = getService(bus, intf, objpath);
64 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
65 if (valueTree.empty())
66 {
67 phosphor::logging::log<phosphor::logging::level::ERR>(
68 "No object implements interface",
69 phosphor::logging::entry("INTF=%s", intf.c_str()));
70 return -1;
71 }
72
Jason M. Bills64796042018-10-03 16:51:55 -070073 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080074 {
75 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
76 if (interface == item.second.end())
77 {
78 continue;
79 }
80
81 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
82 if (property == interface->second.end())
83 {
84 continue;
85 }
86
87 try
88 {
89 Value variant = property->second;
Vernon Mauery8166c8d2019-05-23 11:22:30 -070090 std::string& result = std::get<std::string>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -070091 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080092 {
93 phosphor::logging::log<phosphor::logging::level::ERR>(
94 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080095 return -1;
96 }
Jason M. Bills64796042018-10-03 16:51:55 -070097 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080098 return 0;
99 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700100 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800101 {
Jason M. Bills64796042018-10-03 16:51:55 -0700102 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800103 return -1;
104 }
105 }
106 return -1;
107}
Jason M. Bills64796042018-10-03 16:51:55 -0700108
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800109ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
110 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700111 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800112{
Jason M. Bills64796042018-10-03 16:51:55 -0700113 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800114 // Status code.
115 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700116 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800117 return rc;
118}
119
120// Returns the Chassis Identifier (serial #)
121ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
122 ipmi_request_t request,
123 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700124 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800125 ipmi_context_t context)
126{
127 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700128 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800129 {
Jason M. Bills64796042018-10-03 16:51:55 -0700130 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800131 return IPMI_CC_REQ_DATA_LEN_INVALID;
132 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700133 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
134 if (getChassisSerialNumber(*dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800135 {
Jason M. Bills64796042018-10-03 16:51:55 -0700136 *dataLen = serial.size(); // length will never exceed response length
137 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800138 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700139 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800140 return IPMI_CC_OK;
141 }
Jason M. Bills64796042018-10-03 16:51:55 -0700142 *dataLen = 0;
143 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800144}
145
146ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
147 ipmi_request_t request,
148 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700149 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800150{
151 static constexpr size_t safeBufferLength = 50;
152 char buf[safeBufferLength] = {0};
153 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
154
Jason M. Bills64796042018-10-03 16:51:55 -0700155 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800156 {
Jason M. Bills64796042018-10-03 16:51:55 -0700157 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800158 return IPMI_CC_REQ_DATA_LEN_INVALID;
159 }
160
Jason M. Bills64796042018-10-03 16:51:55 -0700161 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800162
163 snprintf(
164 buf, safeBufferLength,
165 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
166 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
167 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
168 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
169 Data->node3, Data->node2, Data->node1);
170 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
171 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800172
173 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
174 std::string intf = "xyz.openbmc_project.Common.UUID";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700175 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
176 std::string service = getService(*dbus, intf, objpath);
177 setDbusProperty(*dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800178 return IPMI_CC_OK;
179}
180
181ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
182 ipmi_request_t request, ipmi_response_t response,
183 ipmi_data_len_t dataLen, ipmi_context_t context)
184{
185 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
186
Jason M. Bills64796042018-10-03 16:51:55 -0700187 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800188 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800189 *dataLen = 0;
190 return IPMI_CC_REQ_DATA_LEN_INVALID;
191 }
Jason M. Bills64796042018-10-03 16:51:55 -0700192 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800193
Vernon Mauery15419dd2019-05-24 09:40:30 -0700194 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
195 std::string service = getService(*dbus, biosIntf, biosObjPath);
196 setDbusProperty(*dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800197 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
198 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700199 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800200 *dataLen = 1;
201 return IPMI_CC_OK;
202}
203
204ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
205 ipmi_request_t request,
206 ipmi_response_t response,
207 ipmi_data_len_t dataLen, ipmi_context_t context)
208{
209 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
210 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
211
212 if (*dataLen == 0)
213 {
Jason M. Bills64796042018-10-03 16:51:55 -0700214 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800215 return IPMI_CC_REQ_DATA_LEN_INVALID;
216 }
217
218 size_t reqDataLen = *dataLen;
219 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700220 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800221 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800222 return IPMI_CC_INVALID_FIELD_REQUEST;
223 }
224
225 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700226 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800227 {
228 case OEMDevEntityType::biosId:
229 {
230 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
231 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800232 return IPMI_CC_REQ_DATA_LEN_INVALID;
233 }
234
Vernon Mauery15419dd2019-05-24 09:40:30 -0700235 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
236 std::string service = getService(*dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800237 try
238 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700239 Value variant = getDbusProperty(*dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800240 biosIntf, biosProp);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700241 std::string& idString = std::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800242 if (req->offset >= idString.size())
243 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800244 return IPMI_CC_PARM_OUT_OF_RANGE;
245 }
Jason M. Bills64796042018-10-03 16:51:55 -0700246 size_t length = 0;
247 if (req->countToRead > (idString.size() - req->offset))
248 {
249 length = idString.size() - req->offset;
250 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800251 else
252 {
Jason M. Bills64796042018-10-03 16:51:55 -0700253 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800254 }
Jason M. Bills64796042018-10-03 16:51:55 -0700255 std::copy(idString.begin() + req->offset, idString.end(),
256 res->data);
257 res->resDatalen = length;
258 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800259 }
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700260 catch (std::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800261 {
Jason M. Bills64796042018-10-03 16:51:55 -0700262 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800263 return IPMI_CC_UNSPECIFIED_ERROR;
264 }
265 }
266 break;
267
268 case OEMDevEntityType::devVer:
269 case OEMDevEntityType::sdrVer:
270 // TODO:
271 return IPMI_CC_ILLEGAL_COMMAND;
272 default:
273 return IPMI_CC_INVALID_FIELD_REQUEST;
274 }
275 return IPMI_CC_OK;
276}
277
278ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
279 ipmi_request_t request, ipmi_response_t response,
280 ipmi_data_len_t dataLen, ipmi_context_t context)
281{
282 if (*dataLen != 0)
283 {
Jason M. Bills64796042018-10-03 16:51:55 -0700284 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800285 return IPMI_CC_REQ_DATA_LEN_INVALID;
286 }
287
288 *dataLen = 1;
289 uint8_t* res = reinterpret_cast<uint8_t*>(response);
290 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
291 // AIC is available so that BIOS will not timeout repeatly which leads to
292 // slow booting.
293 *res = 0; // Byte1=Count of SlotPosition/FruID records.
294 return IPMI_CC_OK;
295}
296
Jason M. Bills64796042018-10-03 16:51:55 -0700297ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
298 ipmi_request_t request,
299 ipmi_response_t response,
300 ipmi_data_len_t dataLen,
301 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800302{
Jason M. Bills64796042018-10-03 16:51:55 -0700303 GetPowerRestoreDelayRes* resp =
304 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
305
306 if (*dataLen != 0)
307 {
308 *dataLen = 0;
309 return IPMI_CC_REQ_DATA_LEN_INVALID;
310 }
311
Vernon Mauery15419dd2019-05-24 09:40:30 -0700312 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700313 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700314 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
Jason M. Bills64796042018-10-03 16:51:55 -0700315 Value variant =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700316 getDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700317 powerRestoreDelayIntf, powerRestoreDelayProp);
318
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700319 uint16_t delay = std::get<uint16_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700320 resp->byteLSB = delay;
321 resp->byteMSB = delay >> 8;
322
323 *dataLen = sizeof(GetPowerRestoreDelayRes);
324
325 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800326}
327
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800328static uint8_t bcdToDec(uint8_t val)
329{
330 return ((val / 16 * 10) + (val % 16));
331}
332
333// Allows an update utility or system BIOS to send the status of an embedded
334// firmware update attempt to the BMC. After received, BMC will create a logging
335// record.
336ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
337 uint8_t majorRevision,
338 uint8_t minorRevision,
339 uint32_t auxInfo)
340{
341 std::string firmware;
Jason M. Billsdc249272019-04-03 09:58:40 -0700342 int instance = (target & targetInstanceMask) >> targetInstanceShift;
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800343 target = (target & selEvtTargetMask) >> selEvtTargetShift;
344
345 /* make sure the status is 0, 1, or 2 as per the spec */
346 if (status > 2)
347 {
348 return ipmi::response(ipmi::ccInvalidFieldRequest);
349 }
Jason M. Billsdc249272019-04-03 09:58:40 -0700350 /* make sure the target is 0, 1, 2, or 4 as per the spec */
351 if (target > 4 || target == 3)
352 {
353 return ipmi::response(ipmi::ccInvalidFieldRequest);
354 }
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800355 /*orignal OEM command is to record OEM SEL.
356 But openbmc does not support OEM SEL, so we redirect it to redfish event
357 logging. */
358 std::string buildInfo;
359 std::string action;
360 switch (FWUpdateTarget(target))
361 {
362 case FWUpdateTarget::targetBMC:
363 firmware = "BMC";
Jason M. Billsdc249272019-04-03 09:58:40 -0700364 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800365 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
366 " BuildID: " + std::to_string(auxInfo);
367 buildInfo += std::to_string(auxInfo);
368 break;
369 case FWUpdateTarget::targetBIOS:
370 firmware = "BIOS";
371 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700372 "major: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800373 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
374 " minor: " +
375 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
376 " ReleaseNumber: " + // ASCII encoded
377 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
378 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
379 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
380 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
381 break;
382 case FWUpdateTarget::targetME:
383 firmware = "ME";
384 buildInfo =
Jason M. Billsdc249272019-04-03 09:58:40 -0700385 "major: " + std::to_string(majorRevision) + " minor1: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800386 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
387 " minor2: " +
388 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
389 " build1: " +
390 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
391 " build2: " +
392 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
393 break;
394 case FWUpdateTarget::targetOEMEWS:
395 firmware = "EWS";
Jason M. Billsdc249272019-04-03 09:58:40 -0700396 buildInfo = "major: " + std::to_string(majorRevision) + " minor: " +
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800397 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
398 " BuildID: " + std::to_string(auxInfo);
399 break;
400 }
401
Jason M. Billsdc249272019-04-03 09:58:40 -0700402 static const std::string openBMCMessageRegistryVersion("0.1");
403 std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion;
404
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800405 switch (status)
406 {
407 case 0x0:
408 action = "update started";
Jason M. Billsdc249272019-04-03 09:58:40 -0700409 redfishMsgID += ".FirmwareUpdateStarted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800410 break;
411 case 0x1:
412 action = "update completed successfully";
Jason M. Billsdc249272019-04-03 09:58:40 -0700413 redfishMsgID += ".FirmwareUpdateCompleted";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800414 break;
415 case 0x2:
416 action = "update failure";
Jason M. Billsdc249272019-04-03 09:58:40 -0700417 redfishMsgID += ".FirmwareUpdateFailed";
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800418 break;
419 default:
420 action = "unknown";
421 break;
422 }
423
Jason M. Billsdc249272019-04-03 09:58:40 -0700424 std::string firmwareInstanceStr =
425 firmware + " instance: " + std::to_string(instance);
426 std::string message("[firmware update] " + firmwareInstanceStr +
427 " status: <" + action + "> " + buildInfo);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800428
429 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
Jason M. Billsdc249272019-04-03 09:58:40 -0700430 "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(),
431 "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(),
432 buildInfo.c_str(), NULL);
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800433 return ipmi::responseSuccess();
434}
435
Jason M. Bills64796042018-10-03 16:51:55 -0700436ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
437 ipmi_request_t request,
438 ipmi_response_t response,
439 ipmi_data_len_t dataLen,
440 ipmi_context_t context)
441{
442 SetPowerRestoreDelayReq* data =
443 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
444 uint16_t delay = 0;
445
446 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
447 {
448 *dataLen = 0;
449 return IPMI_CC_REQ_DATA_LEN_INVALID;
450 }
451 delay = data->byteMSB;
452 delay = (delay << 8) | data->byteLSB;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700453 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700454 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700455 getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
456 setDbusProperty(*dbus, service, powerRestoreDelayObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700457 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
458 *dataLen = 0;
459
460 return IPMI_CC_OK;
461}
462
463ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
464 ipmi_request_t request,
465 ipmi_response_t response,
466 ipmi_data_len_t dataLen,
467 ipmi_context_t context)
468{
469 GetProcessorErrConfigRes* resp =
470 reinterpret_cast<GetProcessorErrConfigRes*>(response);
471
472 if (*dataLen != 0)
473 {
474 *dataLen = 0;
475 return IPMI_CC_REQ_DATA_LEN_INVALID;
476 }
477
Vernon Mauery15419dd2019-05-24 09:40:30 -0700478 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700479 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700480 getService(*dbus, processorErrConfigIntf, processorErrConfigObjPath);
481 Value variant = getDbusProperty(*dbus, service, processorErrConfigObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700482 processorErrConfigIntf, "ResetCfg");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700483 resp->resetCfg = std::get<uint8_t>(variant);
Jason M. Bills64796042018-10-03 16:51:55 -0700484
485 std::vector<uint8_t> caterrStatus;
Kuiying Wangbc546672018-11-23 15:41:05 +0800486 sdbusplus::message::variant<std::vector<uint8_t>> message;
Jason M. Bills64796042018-10-03 16:51:55 -0700487
488 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700489 dbus->new_method_call(service.c_str(), processorErrConfigObjPath,
490 "org.freedesktop.DBus.Properties", "Get");
Jason M. Bills64796042018-10-03 16:51:55 -0700491
492 method.append(processorErrConfigIntf, "CATERRStatus");
Vernon Mauery15419dd2019-05-24 09:40:30 -0700493 auto reply = dbus->call(method);
Jason M. Bills64796042018-10-03 16:51:55 -0700494
495 try
496 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800497 reply.read(message);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700498 caterrStatus = std::get<std::vector<uint8_t>>(message);
Jason M. Bills64796042018-10-03 16:51:55 -0700499 }
500 catch (sdbusplus::exception_t&)
501 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800502 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills64796042018-10-03 16:51:55 -0700503 "ipmiOEMGetProcessorErrConfig: error on dbus",
504 phosphor::logging::entry("PRORPERTY=CATERRStatus"),
505 phosphor::logging::entry("PATH=%s", processorErrConfigObjPath),
506 phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf));
507 return IPMI_CC_UNSPECIFIED_ERROR;
508 }
509
510 size_t len =
511 maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size();
512 caterrStatus.resize(len);
513 std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus);
514 *dataLen = sizeof(GetProcessorErrConfigRes);
515
516 return IPMI_CC_OK;
517}
518
519ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
520 ipmi_request_t request,
521 ipmi_response_t response,
522 ipmi_data_len_t dataLen,
523 ipmi_context_t context)
524{
525 SetProcessorErrConfigReq* req =
526 reinterpret_cast<SetProcessorErrConfigReq*>(request);
527
528 if (*dataLen != sizeof(SetProcessorErrConfigReq))
529 {
530 *dataLen = 0;
531 return IPMI_CC_REQ_DATA_LEN_INVALID;
532 }
Vernon Mauery15419dd2019-05-24 09:40:30 -0700533 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Jason M. Bills64796042018-10-03 16:51:55 -0700534 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700535 getService(*dbus, processorErrConfigIntf, processorErrConfigObjPath);
536 setDbusProperty(*dbus, service, processorErrConfigObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700537 processorErrConfigIntf, "ResetCfg", req->resetCfg);
538
Vernon Mauery15419dd2019-05-24 09:40:30 -0700539 setDbusProperty(*dbus, service, processorErrConfigObjPath,
Jason M. Bills64796042018-10-03 16:51:55 -0700540 processorErrConfigIntf, "ResetErrorOccurrenceCounts",
541 req->resetErrorOccurrenceCounts);
542 *dataLen = 0;
543
544 return IPMI_CC_OK;
545}
546
Yong Li703922d2018-11-06 13:25:31 +0800547ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
548 ipmi_request_t request,
549 ipmi_response_t response,
550 ipmi_data_len_t dataLen,
551 ipmi_context_t context)
552{
553 GetOEMShutdownPolicyRes* resp =
554 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
555
556 if (*dataLen != 0)
557 {
558 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800559 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800560 *dataLen = 0;
561 return IPMI_CC_REQ_DATA_LEN_INVALID;
562 }
563
564 *dataLen = 0;
565
566 try
567 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700568 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800569 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700570 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
571 Value variant = getDbusProperty(
572 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
573 oemShutdownPolicyObjPathProp);
Yong Li0669d192019-05-06 14:01:46 +0800574
575 if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
576 convertPolicyFromString(std::get<std::string>(variant)) ==
577 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
578 NoShutdownOnOCOT)
579 {
580 resp->policy = 0;
581 }
582 else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
583 convertPolicyFromString(std::get<std::string>(variant)) ==
584 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
585 Policy::ShutdownOnOCOT)
586 {
587 resp->policy = 1;
588 }
589 else
590 {
591 phosphor::logging::log<phosphor::logging::level::ERR>(
592 "oem_set_shutdown_policy: invalid property!",
593 phosphor::logging::entry(
594 "PROP=%s", std::get<std::string>(variant).c_str()));
595 return IPMI_CC_UNSPECIFIED_ERROR;
596 }
Yong Li703922d2018-11-06 13:25:31 +0800597 // TODO needs to check if it is multi-node products,
598 // policy is only supported on node 3/4
599 resp->policySupport = shutdownPolicySupported;
600 }
601 catch (sdbusplus::exception_t& e)
602 {
603 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
604 return IPMI_CC_UNSPECIFIED_ERROR;
605 }
606
607 *dataLen = sizeof(GetOEMShutdownPolicyRes);
608 return IPMI_CC_OK;
609}
610
611ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
612 ipmi_request_t request,
613 ipmi_response_t response,
614 ipmi_data_len_t dataLen,
615 ipmi_context_t context)
616{
617 uint8_t* req = reinterpret_cast<uint8_t*>(request);
Yong Li0669d192019-05-06 14:01:46 +0800618 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy =
619 sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy::
620 NoShutdownOnOCOT;
Yong Li703922d2018-11-06 13:25:31 +0800621
622 // TODO needs to check if it is multi-node products,
623 // policy is only supported on node 3/4
624 if (*dataLen != 1)
625 {
626 phosphor::logging::log<phosphor::logging::level::ERR>(
627 "oem_set_shutdown_policy: invalid input len!");
628 *dataLen = 0;
629 return IPMI_CC_REQ_DATA_LEN_INVALID;
630 }
631
632 *dataLen = 0;
633 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
634 {
635 phosphor::logging::log<phosphor::logging::level::ERR>(
636 "oem_set_shutdown_policy: invalid input!");
637 return IPMI_CC_INVALID_FIELD_REQUEST;
638 }
639
Yong Li0669d192019-05-06 14:01:46 +0800640 if (*req == noShutdownOnOCOT)
641 {
642 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
643 Policy::NoShutdownOnOCOT;
644 }
645 else
646 {
647 policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::
648 Policy::ShutdownOnOCOT;
649 }
650
Yong Li703922d2018-11-06 13:25:31 +0800651 try
652 {
Vernon Mauery15419dd2019-05-24 09:40:30 -0700653 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Yong Li703922d2018-11-06 13:25:31 +0800654 std::string service =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700655 getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
Yong Li0669d192019-05-06 14:01:46 +0800656 setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -0700657 *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf,
Yong Li0669d192019-05-06 14:01:46 +0800658 oemShutdownPolicyObjPathProp,
659 sdbusplus::com::intel::Control::server::convertForMessage(policy));
Yong Li703922d2018-11-06 13:25:31 +0800660 }
661 catch (sdbusplus::exception_t& e)
662 {
663 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
664 return IPMI_CC_UNSPECIFIED_ERROR;
665 }
666
667 return IPMI_CC_OK;
668}
669
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530670/** @brief implementation for check the DHCP or not in IPv4
671 * @param[in] Channel - Channel number
672 * @returns true or false.
673 */
674static bool isDHCPEnabled(uint8_t Channel)
675{
676 try
677 {
678 auto ethdevice = getChannelName(Channel);
679 if (ethdevice.empty())
680 {
681 return false;
682 }
683 auto ethIP = ethdevice + "/ipv4";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700684 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530685 auto ethernetObj =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700686 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
687 auto value = getDbusProperty(*dbus, networkService, ethernetObj.first,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530688 networkIPIntf, "Origin");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700689 if (std::get<std::string>(value) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530690 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
691 {
692 return true;
693 }
694 else
695 {
696 return false;
697 }
698 }
699 catch (sdbusplus::exception_t& e)
700 {
701 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
702 return true;
703 }
704}
705
706/** @brief implementes for check the DHCP or not in IPv6
707 * @param[in] Channel - Channel number
708 * @returns true or false.
709 */
710static bool isDHCPIPv6Enabled(uint8_t Channel)
711{
712
713 try
714 {
715 auto ethdevice = getChannelName(Channel);
716 if (ethdevice.empty())
717 {
718 return false;
719 }
720 auto ethIP = ethdevice + "/ipv6";
Vernon Mauery15419dd2019-05-24 09:40:30 -0700721 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530722 auto objectInfo =
Vernon Mauery15419dd2019-05-24 09:40:30 -0700723 getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP);
724 auto properties = getAllDbusProperties(*dbus, objectInfo.second,
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530725 objectInfo.first, networkIPIntf);
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700726 if (std::get<std::string>(properties["Origin"]) ==
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530727 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
728 {
729 return true;
730 }
731 else
732 {
733 return false;
734 }
735 }
736 catch (sdbusplus::exception_t& e)
737 {
738 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
739 return true;
740 }
741}
742
743/** @brief implementes the creating of default new user
744 * @param[in] userName - new username in 16 bytes.
745 * @param[in] userPassword - new password in 20 bytes
746 * @returns ipmi completion code.
747 */
748ipmi::RspType<> ipmiOEMSetUser2Activation(
749 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
750 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
751{
752 bool userState = false;
753 // Check for System Interface not exist and LAN should be static
754 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
755 {
756 ChannelInfo chInfo;
757 try
758 {
759 getChannelInfo(channel, chInfo);
760 }
761 catch (sdbusplus::exception_t& e)
762 {
763 phosphor::logging::log<phosphor::logging::level::ERR>(
764 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
765 phosphor::logging::entry("MSG: %s", e.description()));
766 return ipmi::response(ipmi::ccUnspecifiedError);
767 }
768 if (chInfo.mediumType ==
769 static_cast<uint8_t>(EChannelMediumType::systemInterface))
770 {
771 phosphor::logging::log<phosphor::logging::level::ERR>(
772 "ipmiOEMSetUser2Activation: system interface exist .");
773 return ipmi::response(ipmi::ccCommandNotAvailable);
774 }
775 else
776 {
777
778 if (chInfo.mediumType ==
779 static_cast<uint8_t>(EChannelMediumType::lan8032))
780 {
781 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
782 {
783 phosphor::logging::log<phosphor::logging::level::ERR>(
784 "ipmiOEMSetUser2Activation: DHCP enabled .");
785 return ipmi::response(ipmi::ccCommandNotAvailable);
786 }
787 }
788 }
789 }
790 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
791 if (ipmi::ccSuccess ==
792 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
793 {
794 if (enabledUsers > 1)
795 {
796 phosphor::logging::log<phosphor::logging::level::ERR>(
797 "ipmiOEMSetUser2Activation: more than one user is enabled.");
798 return ipmi::response(ipmi::ccCommandNotAvailable);
799 }
800 // Check the user 2 is enabled or not
801 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
802 if (userState == true)
803 {
804 phosphor::logging::log<phosphor::logging::level::ERR>(
805 "ipmiOEMSetUser2Activation: user 2 already enabled .");
806 return ipmi::response(ipmi::ccCommandNotAvailable);
807 }
808 }
809 else
810 {
811 return ipmi::response(ipmi::ccUnspecifiedError);
812 }
813
814#if BYTE_ORDER == LITTLE_ENDIAN
815 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
816#endif
817#if BYTE_ORDER == BIG_ENDIAN
818 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
819#endif
820
821 if (ipmi::ccSuccess ==
822 ipmiUserSetUserName(ipmiDefaultUserId,
823 reinterpret_cast<const char*>(userName.data())))
824 {
825 if (ipmi::ccSuccess ==
826 ipmiUserSetUserPassword(
827 ipmiDefaultUserId,
828 reinterpret_cast<const char*>(userPassword.data())))
829 {
830 if (ipmi::ccSuccess ==
831 ipmiUserSetPrivilegeAccess(
832 ipmiDefaultUserId,
833 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
834 privAccess, true))
835 {
836 phosphor::logging::log<phosphor::logging::level::INFO>(
837 "ipmiOEMSetUser2Activation: user created successfully ");
838 return ipmi::responseSuccess();
839 }
840 }
841 // we need to delete the default user id which added in this command as
842 // password / priv setting is failed.
843 ipmiUserSetUserName(ipmiDefaultUserId, "");
844 phosphor::logging::log<phosphor::logging::level::ERR>(
845 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
846 }
847 else
848 {
849 phosphor::logging::log<phosphor::logging::level::ERR>(
850 "ipmiOEMSetUser2Activation: Setting username failed.");
851 }
852
853 return ipmi::response(ipmi::ccCommandNotAvailable);
854}
855
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +0530856/** @brief implementes setting password for special user
857 * @param[in] specialUserIndex
858 * @param[in] userPassword - new password in 20 bytes
859 * @returns ipmi completion code.
860 */
861ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
862 uint8_t specialUserIndex,
863 std::vector<uint8_t> userPassword)
864{
865 ChannelInfo chInfo;
866 try
867 {
868 getChannelInfo(ctx->channel, chInfo);
869 }
870 catch (sdbusplus::exception_t& e)
871 {
872 phosphor::logging::log<phosphor::logging::level::ERR>(
873 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
874 phosphor::logging::entry("MSG: %s", e.description()));
875 return ipmi::responseUnspecifiedError();
876 }
877 if (chInfo.mediumType !=
878 static_cast<uint8_t>(EChannelMediumType::systemInterface))
879 {
880 phosphor::logging::log<phosphor::logging::level::ERR>(
881 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
882 "interface");
883 return ipmi::responseCommandNotAvailable();
884 }
885 if (specialUserIndex != 0)
886 {
887 phosphor::logging::log<phosphor::logging::level::ERR>(
888 "ipmiOEMSetSpecialUserPassword: Invalid user account");
889 return ipmi::responseParmOutOfRange();
890 }
891 constexpr uint8_t minPasswordSizeRequired = 6;
892 if (userPassword.size() < minPasswordSizeRequired ||
893 userPassword.size() > ipmi::maxIpmi20PasswordSize)
894 {
895 return ipmi::responseReqDataLenInvalid();
896 }
897 std::string passwd;
898 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
899 userPassword.size());
900 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
901}
902
Kuiying Wang45f04982018-12-26 09:23:08 +0800903namespace ledAction
904{
905using namespace sdbusplus::xyz::openbmc_project::Led::server;
906std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
907 {Physical::Action::Off, 0x00},
908 {Physical::Action::On, 0x10},
909 {Physical::Action::Blink, 0x01}};
910
911std::map<uint8_t, std::string> offsetObjPath = {
912 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
913
914} // namespace ledAction
915
916int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
917 const std::string& objPath, uint8_t& state)
918{
919 try
920 {
921 std::string service = getService(bus, intf, objPath);
922 Value stateValue =
923 getDbusProperty(bus, service, objPath, intf, "State");
Vernon Mauery8166c8d2019-05-23 11:22:30 -0700924 std::string strState = std::get<std::string>(stateValue);
Kuiying Wang45f04982018-12-26 09:23:08 +0800925 state = ledAction::actionDbusToIpmi.at(
926 sdbusplus::xyz::openbmc_project::Led::server::Physical::
927 convertActionFromString(strState));
928 }
929 catch (sdbusplus::exception::SdBusError& e)
930 {
931 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
932 return -1;
933 }
934 return 0;
935}
936
937ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
938 ipmi_request_t request, ipmi_response_t response,
939 ipmi_data_len_t dataLen, ipmi_context_t context)
940{
941 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
942 // LED Status
943 //[1:0] = Reserved
944 //[3:2] = Status(Amber)
945 //[5:4] = Status(Green)
946 //[7:6] = System Identify
947 // Status definitions:
948 // 00b = Off
949 // 01b = Blink
950 // 10b = On
951 // 11b = invalid
952 if (*dataLen != 0)
953 {
954 phosphor::logging::log<phosphor::logging::level::ERR>(
955 "oem_get_led_status: invalid input len!");
956 *dataLen = 0;
957 return IPMI_CC_REQ_DATA_LEN_INVALID;
958 }
959
960 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
961 *resp = 0;
962 *dataLen = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700963 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Kuiying Wang45f04982018-12-26 09:23:08 +0800964 for (auto it = ledAction::offsetObjPath.begin();
965 it != ledAction::offsetObjPath.end(); ++it)
966 {
967 uint8_t state = 0;
Vernon Mauery15419dd2019-05-24 09:40:30 -0700968 if (-1 == getLEDState(*dbus, ledIntf, it->second, state))
Kuiying Wang45f04982018-12-26 09:23:08 +0800969 {
970 phosphor::logging::log<phosphor::logging::level::ERR>(
971 "oem_get_led_status: fail to get ID LED status!");
972 return IPMI_CC_UNSPECIFIED_ERROR;
973 }
974 *resp |= state << it->first;
975 }
976
977 *dataLen = sizeof(*resp);
978 return IPMI_CC_OK;
979}
980
Yong Li23737fe2019-02-19 08:49:55 +0800981ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
982 ipmi_request_t request,
983 ipmi_response_t response,
984 ipmi_data_len_t dataLen,
985 ipmi_context_t context)
986{
987 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
988 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
989
990 if (*dataLen == 0)
991 {
992 phosphor::logging::log<phosphor::logging::level::ERR>(
993 "CfgHostSerial: invalid input len!",
994 phosphor::logging::entry("LEN=%d", *dataLen));
995 return IPMI_CC_REQ_DATA_LEN_INVALID;
996 }
997
998 switch (req->command)
999 {
1000 case getHostSerialCfgCmd:
1001 {
1002 if (*dataLen != 1)
1003 {
1004 phosphor::logging::log<phosphor::logging::level::ERR>(
1005 "CfgHostSerial: invalid input len!");
1006 *dataLen = 0;
1007 return IPMI_CC_REQ_DATA_LEN_INVALID;
1008 }
1009
1010 *dataLen = 0;
1011
1012 boost::process::ipstream is;
1013 std::vector<std::string> data;
1014 std::string line;
1015 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
1016 boost::process::std_out > is);
1017
1018 while (c1.running() && std::getline(is, line) && !line.empty())
1019 {
1020 data.push_back(line);
1021 }
1022
1023 c1.wait();
1024 if (c1.exit_code())
1025 {
1026 phosphor::logging::log<phosphor::logging::level::ERR>(
1027 "CfgHostSerial:: error on execute",
1028 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
1029 // Using the default value
1030 *resp = 0;
1031 }
1032 else
1033 {
1034 if (data.size() != 1)
1035 {
1036 phosphor::logging::log<phosphor::logging::level::ERR>(
1037 "CfgHostSerial:: error on read env");
1038 return IPMI_CC_UNSPECIFIED_ERROR;
1039 }
1040 try
1041 {
1042 unsigned long tmp = std::stoul(data[0]);
1043 if (tmp > std::numeric_limits<uint8_t>::max())
1044 {
1045 throw std::out_of_range("Out of range");
1046 }
1047 *resp = static_cast<uint8_t>(tmp);
1048 }
1049 catch (const std::invalid_argument& e)
1050 {
1051 phosphor::logging::log<phosphor::logging::level::ERR>(
1052 "invalid config ",
1053 phosphor::logging::entry("ERR=%s", e.what()));
1054 return IPMI_CC_UNSPECIFIED_ERROR;
1055 }
1056 catch (const std::out_of_range& e)
1057 {
1058 phosphor::logging::log<phosphor::logging::level::ERR>(
1059 "out_of_range config ",
1060 phosphor::logging::entry("ERR=%s", e.what()));
1061 return IPMI_CC_UNSPECIFIED_ERROR;
1062 }
1063 }
1064
1065 *dataLen = 1;
1066 break;
1067 }
1068 case setHostSerialCfgCmd:
1069 {
1070 if (*dataLen != sizeof(CfgHostSerialReq))
1071 {
1072 phosphor::logging::log<phosphor::logging::level::ERR>(
1073 "CfgHostSerial: invalid input len!");
1074 *dataLen = 0;
1075 return IPMI_CC_REQ_DATA_LEN_INVALID;
1076 }
1077
1078 *dataLen = 0;
1079
1080 if (req->parameter > HostSerialCfgParamMax)
1081 {
1082 phosphor::logging::log<phosphor::logging::level::ERR>(
1083 "CfgHostSerial: invalid input!");
1084 return IPMI_CC_INVALID_FIELD_REQUEST;
1085 }
1086
1087 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1088 std::to_string(req->parameter));
1089
1090 c1.wait();
1091 if (c1.exit_code())
1092 {
1093 phosphor::logging::log<phosphor::logging::level::ERR>(
1094 "CfgHostSerial:: error on execute",
1095 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1096 return IPMI_CC_UNSPECIFIED_ERROR;
1097 }
1098 break;
1099 }
1100 default:
1101 phosphor::logging::log<phosphor::logging::level::ERR>(
1102 "CfgHostSerial: invalid input!");
1103 *dataLen = 0;
1104 return IPMI_CC_INVALID_FIELD_REQUEST;
1105 }
1106
1107 return IPMI_CC_OK;
1108}
1109
James Feist91244a62019-02-19 15:04:54 -08001110constexpr const char* thermalModeInterface =
1111 "xyz.openbmc_project.Control.ThermalMode";
1112constexpr const char* thermalModePath =
1113 "/xyz/openbmc_project/control/thermal_mode";
1114
1115bool getFanProfileInterface(
1116 sdbusplus::bus::bus& bus,
1117 boost::container::flat_map<
1118 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1119{
1120 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1121 "GetAll");
1122 call.append(thermalModeInterface);
1123 try
1124 {
1125 auto data = bus.call(call);
1126 data.read(resp);
1127 }
1128 catch (sdbusplus::exception_t& e)
1129 {
1130 phosphor::logging::log<phosphor::logging::level::ERR>(
1131 "getFanProfileInterface: can't get thermal mode!",
1132 phosphor::logging::entry("ERR=%s", e.what()));
1133 return false;
1134 }
1135 return true;
1136}
1137
1138ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1139 ipmi_request_t request, ipmi_response_t response,
1140 ipmi_data_len_t dataLen, ipmi_context_t context)
1141{
1142
1143 if (*dataLen < 2 || *dataLen > 7)
1144 {
1145 phosphor::logging::log<phosphor::logging::level::ERR>(
1146 "ipmiOEMSetFanConfig: invalid input len!");
1147 *dataLen = 0;
1148 return IPMI_CC_REQ_DATA_LEN_INVALID;
1149 }
1150
1151 // todo: tell bios to only send first 2 bytes
1152
1153 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1154 boost::container::flat_map<
1155 std::string, std::variant<std::vector<std::string>, std::string>>
1156 profileData;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001157 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1158 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001159 {
1160 return IPMI_CC_UNSPECIFIED_ERROR;
1161 }
1162
1163 std::vector<std::string>* supported =
1164 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1165 if (supported == nullptr)
1166 {
1167 return IPMI_CC_INVALID_FIELD_REQUEST;
1168 }
1169 std::string mode;
1170 if (req->flags &
1171 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1172 {
1173 bool performanceMode =
1174 (req->flags & (1 << static_cast<uint8_t>(
1175 setFanProfileFlags::performAcousSelect))) > 0;
1176
1177 if (performanceMode)
1178 {
1179
1180 if (std::find(supported->begin(), supported->end(),
1181 "Performance") != supported->end())
1182 {
1183 mode = "Performance";
1184 }
1185 }
1186 else
1187 {
1188
1189 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1190 supported->end())
1191 {
1192 mode = "Acoustic";
1193 }
1194 }
1195 if (mode.empty())
1196 {
1197 return IPMI_CC_INVALID_FIELD_REQUEST;
1198 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001199 setDbusProperty(*dbus, settingsBusName, thermalModePath,
James Feist91244a62019-02-19 15:04:54 -08001200 thermalModeInterface, "Current", mode);
1201 }
1202
1203 return IPMI_CC_OK;
1204}
1205
1206ipmi_ret_t ipmiOEMGetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1207 ipmi_request_t request, ipmi_response_t response,
1208 ipmi_data_len_t dataLen, ipmi_context_t context)
1209{
1210
1211 if (*dataLen > 1)
1212 {
1213 phosphor::logging::log<phosphor::logging::level::ERR>(
1214 "ipmiOEMGetFanConfig: invalid input len!");
1215 *dataLen = 0;
1216 return IPMI_CC_REQ_DATA_LEN_INVALID;
1217 }
1218
1219 // todo: talk to bios about needing less information
1220
1221 GetFanConfigResp* resp = reinterpret_cast<GetFanConfigResp*>(response);
1222 *dataLen = sizeof(GetFanConfigResp);
1223
1224 boost::container::flat_map<
1225 std::string, std::variant<std::vector<std::string>, std::string>>
1226 profileData;
1227
Vernon Mauery15419dd2019-05-24 09:40:30 -07001228 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
1229 if (!getFanProfileInterface(*dbus, profileData))
James Feist91244a62019-02-19 15:04:54 -08001230 {
1231 return IPMI_CC_UNSPECIFIED_ERROR;
1232 }
1233
1234 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1235
1236 if (current == nullptr)
1237 {
1238 phosphor::logging::log<phosphor::logging::level::ERR>(
1239 "ipmiOEMGetFanConfig: can't get current mode!");
1240 return IPMI_CC_UNSPECIFIED_ERROR;
1241 }
1242 bool performance = (*current == "Performance");
1243
1244 if (performance)
1245 {
1246 resp->flags |= 1 << 2;
1247 }
1248
1249 return IPMI_CC_OK;
1250}
1251
James Feist5f957ca2019-03-14 15:33:55 -07001252constexpr const char* cfmLimitSettingPath =
1253 "/xyz/openbmc_project/control/cfm_limit";
1254constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001255constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feistacc8a4e2019-04-02 14:23:57 -07001256constexpr const char* pidConfigurationIface =
1257 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001258
1259static std::string getExitAirConfigPath()
1260{
Vernon Mauery15419dd2019-05-24 09:40:30 -07001261 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistfaa4f222019-03-21 16:21:55 -07001262 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001263 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1264 "/xyz/openbmc_project/object_mapper",
1265 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistfaa4f222019-03-21 16:21:55 -07001266
James Feistacc8a4e2019-04-02 14:23:57 -07001267 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001268 std::string path;
1269 GetSubTreeType resp;
1270 try
1271 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001272 auto reply = dbus->call(method);
James Feistfaa4f222019-03-21 16:21:55 -07001273 reply.read(resp);
1274 }
1275 catch (sdbusplus::exception_t&)
1276 {
1277 phosphor::logging::log<phosphor::logging::level::ERR>(
1278 "ipmiOEMGetFscParameter: mapper error");
1279 };
1280 auto config = std::find_if(resp.begin(), resp.end(), [](const auto& pair) {
1281 return pair.first.find("Exit_Air") != std::string::npos;
1282 });
1283 if (config != resp.end())
1284 {
1285 path = std::move(config->first);
1286 }
1287 return path;
1288}
James Feist5f957ca2019-03-14 15:33:55 -07001289
James Feistacc8a4e2019-04-02 14:23:57 -07001290// flat map to make alphabetical
1291static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1292{
1293 boost::container::flat_map<std::string, PropertyMap> ret;
Vernon Mauery15419dd2019-05-24 09:40:30 -07001294 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001295 auto method =
Vernon Mauery15419dd2019-05-24 09:40:30 -07001296 dbus->new_method_call("xyz.openbmc_project.ObjectMapper",
1297 "/xyz/openbmc_project/object_mapper",
1298 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
James Feistacc8a4e2019-04-02 14:23:57 -07001299
1300 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1301 GetSubTreeType resp;
1302
1303 try
1304 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001305 auto reply = dbus->call(method);
James Feistacc8a4e2019-04-02 14:23:57 -07001306 reply.read(resp);
1307 }
1308 catch (sdbusplus::exception_t&)
1309 {
1310 phosphor::logging::log<phosphor::logging::level::ERR>(
1311 "getFanConfigPaths: mapper error");
1312 };
1313 for (const auto& [path, objects] : resp)
1314 {
1315 if (objects.empty())
1316 {
1317 continue; // should be impossible
1318 }
Zhu, Yungebe560b02019-04-21 21:19:21 -04001319
1320 try
1321 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001322 ret.emplace(path,
1323 getAllDbusProperties(*dbus, objects[0].first, path,
1324 pidConfigurationIface));
Zhu, Yungebe560b02019-04-21 21:19:21 -04001325 }
1326 catch (sdbusplus::exception_t& e)
1327 {
1328 phosphor::logging::log<phosphor::logging::level::ERR>(
1329 "getPidConfigs: can't get DbusProperties!",
1330 phosphor::logging::entry("ERR=%s", e.what()));
1331 }
James Feistacc8a4e2019-04-02 14:23:57 -07001332 }
1333 return ret;
1334}
1335
1336ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1337{
1338 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1339 if (data.empty())
1340 {
1341 return ipmi::responseResponseError();
1342 }
1343 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1344 for (const auto& [_, pid] : data)
1345 {
1346 auto findClass = pid.find("Class");
1347 if (findClass == pid.end())
1348 {
1349 phosphor::logging::log<phosphor::logging::level::ERR>(
1350 "ipmiOEMGetFscParameter: found illegal pid "
1351 "configurations");
1352 return ipmi::responseResponseError();
1353 }
1354 std::string type = std::get<std::string>(findClass->second);
1355 if (type == "fan")
1356 {
1357 auto findOutLimit = pid.find("OutLimitMin");
1358 if (findOutLimit == pid.end())
1359 {
1360 phosphor::logging::log<phosphor::logging::level::ERR>(
1361 "ipmiOEMGetFscParameter: found illegal pid "
1362 "configurations");
1363 return ipmi::responseResponseError();
1364 }
1365 // get the min out of all the offsets
1366 minOffset = std::min(
1367 minOffset,
1368 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1369 }
1370 }
1371 if (minOffset == std::numeric_limits<uint8_t>::max())
1372 {
1373 phosphor::logging::log<phosphor::logging::level::ERR>(
1374 "ipmiOEMGetFscParameter: found no fan configurations!");
1375 return ipmi::responseResponseError();
1376 }
1377
1378 return ipmi::responseSuccess(minOffset);
1379}
1380
1381ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1382{
1383 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1384 if (data.empty())
1385 {
1386
1387 phosphor::logging::log<phosphor::logging::level::ERR>(
1388 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1389 return ipmi::responseResponseError();
1390 }
1391
Vernon Mauery15419dd2019-05-24 09:40:30 -07001392 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001393 bool found = false;
1394 for (const auto& [path, pid] : data)
1395 {
1396 auto findClass = pid.find("Class");
1397 if (findClass == pid.end())
1398 {
1399
1400 phosphor::logging::log<phosphor::logging::level::ERR>(
1401 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1402 "configurations");
1403 return ipmi::responseResponseError();
1404 }
1405 std::string type = std::get<std::string>(findClass->second);
1406 if (type == "fan")
1407 {
1408 auto findOutLimit = pid.find("OutLimitMin");
1409 if (findOutLimit == pid.end())
1410 {
1411
1412 phosphor::logging::log<phosphor::logging::level::ERR>(
1413 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1414 "configurations");
1415 return ipmi::responseResponseError();
1416 }
Vernon Mauery15419dd2019-05-24 09:40:30 -07001417 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001418 path, pidConfigurationIface, "OutLimitMin",
1419 static_cast<double>(offset));
1420 found = true;
1421 }
1422 }
1423 if (!found)
1424 {
1425 phosphor::logging::log<phosphor::logging::level::ERR>(
1426 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1427 return ipmi::responseResponseError();
1428 }
1429
1430 return ipmi::responseSuccess();
1431}
1432
1433ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1434 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001435{
1436 constexpr const size_t disableLimiting = 0x0;
1437
Vernon Mauery15419dd2019-05-24 09:40:30 -07001438 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001439 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001440 {
James Feistacc8a4e2019-04-02 14:23:57 -07001441 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001442 {
James Feistfaa4f222019-03-21 16:21:55 -07001443 std::string path = getExitAirConfigPath();
Vernon Mauery15419dd2019-05-24 09:40:30 -07001444 ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001445 path, pidConfigurationIface, "SetPoint",
1446 static_cast<double>(param2));
1447 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001448 }
1449 else
1450 {
James Feistacc8a4e2019-04-02 14:23:57 -07001451 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001452 }
1453 }
James Feistacc8a4e2019-04-02 14:23:57 -07001454 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001455 {
James Feistacc8a4e2019-04-02 14:23:57 -07001456 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001457
1458 // must be greater than 50 based on eps
1459 if (cfm < 50 && cfm != disableLimiting)
1460 {
James Feistacc8a4e2019-04-02 14:23:57 -07001461 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001462 }
1463
1464 try
1465 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001466 ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath,
James Feist5f957ca2019-03-14 15:33:55 -07001467 cfmLimitIface, "Limit",
1468 static_cast<double>(cfm));
1469 }
1470 catch (sdbusplus::exception_t& e)
1471 {
1472 phosphor::logging::log<phosphor::logging::level::ERR>(
1473 "ipmiOEMSetFscParameter: can't set cfm setting!",
1474 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001475 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001476 }
James Feistacc8a4e2019-04-02 14:23:57 -07001477 return ipmi::responseSuccess();
1478 }
1479 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1480 {
1481 constexpr const size_t maxDomainCount = 8;
1482 uint8_t requestedDomainMask = param1;
1483 boost::container::flat_map data = getPidConfigs();
1484 if (data.empty())
1485 {
1486
1487 phosphor::logging::log<phosphor::logging::level::ERR>(
1488 "ipmiOEMSetFscParameter: found no pid configurations!");
1489 return ipmi::responseResponseError();
1490 }
1491 size_t count = 0;
1492 for (const auto& [path, pid] : data)
1493 {
1494 auto findClass = pid.find("Class");
1495 if (findClass == pid.end())
1496 {
1497
1498 phosphor::logging::log<phosphor::logging::level::ERR>(
1499 "ipmiOEMSetFscParameter: found illegal pid "
1500 "configurations");
1501 return ipmi::responseResponseError();
1502 }
1503 std::string type = std::get<std::string>(findClass->second);
1504 if (type == "fan")
1505 {
1506 if (requestedDomainMask & (1 << count))
1507 {
1508 ipmi::setDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001509 *dbus, "xyz.openbmc_project.EntityManager", path,
James Feistacc8a4e2019-04-02 14:23:57 -07001510 pidConfigurationIface, "OutLimitMax",
1511 static_cast<double>(param2));
1512 }
1513 count++;
1514 }
1515 }
1516 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001517 }
1518 else
1519 {
1520 // todo other command parts possibly
1521 // tcontrol is handled in peci now
1522 // fan speed offset not implemented yet
1523 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001524 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001525 }
1526}
1527
James Feistacc8a4e2019-04-02 14:23:57 -07001528ipmi::RspType<
1529 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1530 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001531{
James Feistfaa4f222019-03-21 16:21:55 -07001532 constexpr uint8_t legacyDefaultExitAirLimit = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001533
Vernon Mauery15419dd2019-05-24 09:40:30 -07001534 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
James Feistacc8a4e2019-04-02 14:23:57 -07001535 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001536 {
James Feistacc8a4e2019-04-02 14:23:57 -07001537 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001538 {
James Feistacc8a4e2019-04-02 14:23:57 -07001539 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001540 }
1541
James Feistacc8a4e2019-04-02 14:23:57 -07001542 if (*param != legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001543 {
James Feistacc8a4e2019-04-02 14:23:57 -07001544 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001545 }
1546 uint8_t setpoint = legacyDefaultExitAirLimit;
1547 std::string path = getExitAirConfigPath();
1548 if (path.size())
1549 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001550 Value val = ipmi::getDbusProperty(
1551 *dbus, "xyz.openbmc_project.EntityManager", path,
1552 pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001553 setpoint = std::floor(std::get<double>(val) + 0.5);
1554 }
1555
1556 // old implementation used to return the "default" and current, we
1557 // don't make the default readily available so just make both the
1558 // same
James Feistfaa4f222019-03-21 16:21:55 -07001559
James Feistacc8a4e2019-04-02 14:23:57 -07001560 return ipmi::responseSuccess(
1561 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001562 }
James Feistacc8a4e2019-04-02 14:23:57 -07001563 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1564 {
1565 constexpr const size_t maxDomainCount = 8;
1566
1567 if (!param)
1568 {
1569 return ipmi::responseReqDataLenInvalid();
1570 }
1571 uint8_t requestedDomain = *param;
1572 if (requestedDomain >= maxDomainCount)
1573 {
1574 return ipmi::responseInvalidFieldRequest();
1575 }
1576
1577 boost::container::flat_map data = getPidConfigs();
1578 if (data.empty())
1579 {
1580 phosphor::logging::log<phosphor::logging::level::ERR>(
1581 "ipmiOEMGetFscParameter: found no pid configurations!");
1582 return ipmi::responseResponseError();
1583 }
1584 size_t count = 0;
1585 for (const auto& [_, pid] : data)
1586 {
1587 auto findClass = pid.find("Class");
1588 if (findClass == pid.end())
1589 {
1590 phosphor::logging::log<phosphor::logging::level::ERR>(
1591 "ipmiOEMGetFscParameter: found illegal pid "
1592 "configurations");
1593 return ipmi::responseResponseError();
1594 }
1595 std::string type = std::get<std::string>(findClass->second);
1596 if (type == "fan")
1597 {
1598 if (requestedDomain == count)
1599 {
1600 auto findOutLimit = pid.find("OutLimitMax");
1601 if (findOutLimit == pid.end())
1602 {
1603 phosphor::logging::log<phosphor::logging::level::ERR>(
1604 "ipmiOEMGetFscParameter: found illegal pid "
1605 "configurations");
1606 return ipmi::responseResponseError();
1607 }
1608
1609 return ipmi::responseSuccess(
1610 static_cast<uint8_t>(std::floor(
1611 std::get<double>(findOutLimit->second) + 0.5)));
1612 }
1613 else
1614 {
1615 count++;
1616 }
1617 }
1618 }
1619
1620 return ipmi::responseInvalidFieldRequest();
1621 }
1622 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001623 {
1624
1625 /*
1626 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001627 previous behavior didn't seem to prevent this, ignore the check for
1628 now.
James Feist5f957ca2019-03-14 15:33:55 -07001629
James Feistacc8a4e2019-04-02 14:23:57 -07001630 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001631 {
1632 phosphor::logging::log<phosphor::logging::level::ERR>(
1633 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001634 return IPMI_CC_REQ_DATA_LEN_INVALID;
1635 }
1636 */
1637 Value cfmLimit;
1638 Value cfmMaximum;
1639 try
1640 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001641 cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName,
James Feist5f957ca2019-03-14 15:33:55 -07001642 cfmLimitSettingPath, cfmLimitIface,
1643 "Limit");
1644 cfmMaximum = ipmi::getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001645 *dbus, "xyz.openbmc_project.ExitAirTempSensor",
James Feist5f957ca2019-03-14 15:33:55 -07001646 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1647 }
1648 catch (sdbusplus::exception_t& e)
1649 {
1650 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001651 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001652 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001653 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001654 }
1655
James Feistacc8a4e2019-04-02 14:23:57 -07001656 double cfmMax = std::get<double>(cfmMaximum);
1657 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001658
James Feistacc8a4e2019-04-02 14:23:57 -07001659 cfmLim = std::floor(cfmLim + 0.5);
1660 cfmMax = std::floor(cfmMax + 0.5);
1661 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1662 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001663
James Feistacc8a4e2019-04-02 14:23:57 -07001664 return ipmi::responseSuccess(
1665 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001666 }
James Feistacc8a4e2019-04-02 14:23:57 -07001667
James Feist5f957ca2019-03-14 15:33:55 -07001668 else
1669 {
1670 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001671 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001672 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001673 }
1674}
1675
Zhu, Yungebe560b02019-04-21 21:19:21 -04001676ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType,
1677 uint8_t faultState,
1678 uint8_t faultGroup,
1679 std::array<uint8_t, 8>& ledStateData)
1680{
1681 static constexpr const char* objpath = "/xyz/openbmc_project/EntityManager";
1682 static constexpr const char* intf = "xyz.openbmc_project.EntityManager";
1683 constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max);
1684 static const std::array<std::string, maxFaultType> faultNames = {
1685 "faultFan", "faultTemp", "faultPower",
1686 "faultDriveSlot", "faultSoftware", "faultMemory"};
1687 static constexpr const char* sysGpioPath = "/sys/class/gpio/gpio";
1688 static constexpr const char* postfixValue = "/value";
1689
1690 constexpr uint8_t maxFaultSource = 0x4;
1691 constexpr uint8_t skipLEDs = 0xFF;
1692 constexpr uint8_t pinSize = 64;
1693 constexpr uint8_t groupSize = 16;
1694
1695 std::vector<uint16_t> ledFaultPins(pinSize, 0xFFFF);
1696 uint64_t resFIndex = 0;
1697 std::string resFType;
1698 std::string service;
1699 ObjectValueTree valueTree;
1700
1701 // Validate the source, fault type
1702 if ((sourceId >= maxFaultSource) ||
1703 (faultType >= static_cast<int8_t>(RemoteFaultType::max)) ||
1704 (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) ||
1705 (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup)))
1706 {
1707 return ipmi::responseParmOutOfRange();
1708 }
1709
Vernon Mauery15419dd2019-05-24 09:40:30 -07001710 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Zhu, Yungebe560b02019-04-21 21:19:21 -04001711 try
1712 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001713 service = getService(*dbus, intf, objpath);
1714 valueTree = getManagedObjects(*dbus, service, "/");
Zhu, Yungebe560b02019-04-21 21:19:21 -04001715 }
1716 catch (const std::exception& e)
1717 {
1718 phosphor::logging::log<phosphor::logging::level::ERR>(
1719 "No object implements interface",
1720 phosphor::logging::entry("SERVICE=%s", service.c_str()),
1721 phosphor::logging::entry("INTF=%s", intf));
1722 return ipmi::responseResponseError();
1723 }
1724
1725 if (valueTree.empty())
1726 {
1727 phosphor::logging::log<phosphor::logging::level::ERR>(
1728 "No object implements interface",
1729 phosphor::logging::entry("INTF=%s", intf));
1730 return ipmi::responseResponseError();
1731 }
1732
1733 for (const auto& item : valueTree)
1734 {
1735 // find LedFault configuration
1736 auto interface =
1737 item.second.find("xyz.openbmc_project.Configuration.LedFault");
1738 if (interface == item.second.end())
1739 {
1740 continue;
1741 }
1742
1743 // find matched fault type: faultMemmory / faultFan
1744 // find LedGpioPins/FaultIndex configuration
1745 auto propertyFaultType = interface->second.find("FaultType");
1746 auto propertyFIndex = interface->second.find("FaultIndex");
1747 auto ledIndex = interface->second.find("LedGpioPins");
1748
1749 if (propertyFaultType == interface->second.end() ||
1750 propertyFIndex == interface->second.end() ||
1751 ledIndex == interface->second.end())
1752 {
1753 continue;
1754 }
1755
1756 try
1757 {
1758 Value valIndex = propertyFIndex->second;
1759 resFIndex = std::get<uint64_t>(valIndex);
1760
1761 Value valFType = propertyFaultType->second;
1762 resFType = std::get<std::string>(valFType);
1763 }
1764 catch (const std::bad_variant_access& e)
1765 {
1766 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1767 return ipmi::responseResponseError();
1768 }
1769 // find the matched requested fault type: faultMemmory or faultFan
1770 if (resFType != faultNames[faultType])
1771 {
1772 continue;
1773 }
1774
1775 // read LedGpioPins data
1776 std::vector<uint64_t> ledgpios;
1777 std::variant<std::vector<uint64_t>> message;
1778
Vernon Mauery15419dd2019-05-24 09:40:30 -07001779 auto method = dbus->new_method_call(
Zhu, Yungebe560b02019-04-21 21:19:21 -04001780 service.c_str(), (std::string(item.first)).c_str(),
1781 "org.freedesktop.DBus.Properties", "Get");
1782
1783 method.append("xyz.openbmc_project.Configuration.LedFault",
1784 "LedGpioPins");
1785
1786 try
1787 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001788 auto reply = dbus->call(method);
Zhu, Yungebe560b02019-04-21 21:19:21 -04001789 reply.read(message);
1790 ledgpios = std::get<std::vector<uint64_t>>(message);
1791 }
1792 catch (std::exception& e)
1793 {
1794 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
1795 return ipmi::responseResponseError();
1796 }
1797
1798 // Check the size to be sure it will never overflow on groupSize
1799 if (ledgpios.size() > groupSize)
1800 {
1801 phosphor::logging::log<phosphor::logging::level::ERR>(
1802 "Fault gpio Pins out of range!");
1803 return ipmi::responseParmOutOfRange();
1804 }
1805 // Store data, according to command data bit index order
1806 for (int i = 0; i < ledgpios.size(); i++)
1807 {
1808 ledFaultPins[i + groupSize * resFIndex] = ledgpios[i];
1809 }
1810 }
1811
1812 switch (RemoteFaultType(faultType))
1813 {
1814 case (RemoteFaultType::fan):
1815 case (RemoteFaultType::memory):
1816 {
1817 if (faultGroup == skipLEDs)
1818 {
1819 return ipmi::responseSuccess();
1820 }
1821
1822 uint64_t ledState = 0;
1823 // calculate led state bit filed count, each byte has 8bits
1824 // the maximum bits will be 8 * 8 bits
1825 constexpr uint8_t size = sizeof(ledStateData) * 8;
1826 for (int i = 0; i < sizeof(ledStateData); i++)
1827 {
1828 ledState = (uint64_t)(ledState << 8);
1829 ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]);
1830 }
1831
1832 std::bitset<size> ledStateBits(ledState);
1833 std::string gpioValue;
1834 for (int i = 0; i < size; i++)
1835 { // skip invalid value
1836 if (ledFaultPins[i] == 0xFFFF)
1837 {
1838 continue;
1839 }
1840
1841 std::string device = sysGpioPath +
1842 std::to_string(ledFaultPins[i]) +
1843 postfixValue;
1844 std::fstream gpioFile;
1845
1846 gpioFile.open(device, std::ios::out);
1847
1848 if (!gpioFile.good())
1849 {
1850 phosphor::logging::log<phosphor::logging::level::ERR>(
1851 "Not Find Led Gpio Device!",
1852 phosphor::logging::entry("DEVICE=%s", device.c_str()));
1853 return ipmi::responseResponseError();
1854 }
1855 gpioFile << std::to_string(
1856 static_cast<uint8_t>(ledStateBits[i]));
1857 gpioFile.close();
1858 }
1859 break;
1860 }
1861 default:
1862 {
1863 // now only support two fault types
1864 return ipmi::responseParmOutOfRange();
1865 }
1866 }
1867
1868 return ipmi::responseSuccess();
1869}
1870
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301871ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId()
1872{
1873 uint8_t prodId = 0;
1874 try
1875 {
Vernon Mauery15419dd2019-05-24 09:40:30 -07001876 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301877 const DbusObjectInfo& object = getDbusObject(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001878 *dbus, "xyz.openbmc_project.Inventory.Item.Board",
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301879 "/xyz/openbmc_project/inventory/system/board/", "Baseboard");
1880 const Value& propValue = getDbusProperty(
Vernon Mauery15419dd2019-05-24 09:40:30 -07001881 *dbus, object.second, object.first,
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05301882 "xyz.openbmc_project.Inventory.Item.Board", "ProductId");
1883 prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue));
1884 }
1885 catch (std::exception& e)
1886 {
1887 phosphor::logging::log<phosphor::logging::level::ERR>(
1888 "ipmiOEMReadBoardProductId: Product ID read failed!",
1889 phosphor::logging::entry("ERR=%s", e.what()));
1890 }
1891 return ipmi::responseSuccess(prodId);
1892}
1893
Vernon Mauery4ac799d2019-05-20 15:50:37 -07001894ipmi::RspType<uint8_t /* restore status */>
1895 ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd)
1896{
1897 static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'};
1898
1899 if (clr != expClr)
1900 {
1901 return ipmi::responseInvalidFieldRequest();
1902 }
1903 constexpr uint8_t cmdStatus = 0;
1904 constexpr uint8_t cmdDefaultRestore = 0xaa;
1905 constexpr uint8_t cmdFullRestore = 0xbb;
1906 constexpr uint8_t cmdFormat = 0xcc;
1907
1908 constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op";
1909
1910 switch (cmd)
1911 {
1912 case cmdStatus:
1913 break;
1914 case cmdDefaultRestore:
1915 case cmdFullRestore:
1916 case cmdFormat:
1917 {
1918 // write file to rwfs root
1919 int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3
1920 std::ofstream restoreFile(restoreOpFname);
1921 if (!restoreFile)
1922 {
1923 return ipmi::responseUnspecifiedError();
1924 }
1925 restoreFile << value << "\n";
1926 break;
1927 }
1928 default:
1929 return ipmi::responseInvalidFieldRequest();
1930 }
1931
1932 constexpr uint8_t restorePending = 0;
1933 constexpr uint8_t restoreComplete = 1;
1934
1935 uint8_t restoreStatus = std::filesystem::exists(restoreOpFname)
1936 ? restorePending
1937 : restoreComplete;
1938 return ipmi::responseSuccess(restoreStatus);
1939}
1940
Jason M. Bills64796042018-10-03 16:51:55 -07001941static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001942{
1943 phosphor::logging::log<phosphor::logging::level::INFO>(
1944 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07001945 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
1946 ipmiOEMWildcard,
1947 PRIVILEGE_USER); // wildcard default handler
1948 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
1949 ipmiOEMWildcard,
1950 PRIVILEGE_USER); // wildcard default handler
1951 ipmiPrintAndRegister(
1952 netfnIntcOEMGeneral,
1953 static_cast<ipmi_cmd_t>(
1954 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
1955 NULL, ipmiOEMGetChassisIdentifier,
1956 PRIVILEGE_USER); // get chassis identifier
1957 ipmiPrintAndRegister(
1958 netfnIntcOEMGeneral,
1959 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
1960 NULL, ipmiOEMSetSystemGUID,
1961 PRIVILEGE_ADMIN); // set system guid
1962 ipmiPrintAndRegister(
1963 netfnIntcOEMGeneral,
1964 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
1965 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
1966 ipmiPrintAndRegister(netfnIntcOEMGeneral,
1967 static_cast<ipmi_cmd_t>(
1968 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
1969 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
1970 ipmiPrintAndRegister(
1971 netfnIntcOEMGeneral,
1972 static_cast<ipmi_cmd_t>(
1973 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
1974 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08001975
1976 ipmi::registerHandler(
1977 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1978 static_cast<ipmi::Cmd>(
1979 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
1980 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
1981
Jason M. Bills64796042018-10-03 16:51:55 -07001982 ipmiPrintAndRegister(
1983 netfnIntcOEMGeneral,
1984 static_cast<ipmi_cmd_t>(
1985 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
1986 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
1987 ipmiPrintAndRegister(
1988 netfnIntcOEMGeneral,
1989 static_cast<ipmi_cmd_t>(
1990 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
1991 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301992
1993 ipmi::registerHandler(
1994 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1995 static_cast<ipmi::Cmd>(
1996 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
1997 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
1998
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301999 ipmi::registerHandler(
2000 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
2001 static_cast<ipmi::Cmd>(
2002 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
2003 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
2004
Jason M. Bills64796042018-10-03 16:51:55 -07002005 ipmiPrintAndRegister(
2006 netfnIntcOEMGeneral,
2007 static_cast<ipmi_cmd_t>(
2008 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
2009 NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
2010 ipmiPrintAndRegister(
2011 netfnIntcOEMGeneral,
2012 static_cast<ipmi_cmd_t>(
2013 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
2014 NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
Yong Li703922d2018-11-06 13:25:31 +08002015 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2016 static_cast<ipmi_cmd_t>(
2017 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
2018 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
2019 ipmiPrintAndRegister(netfnIntcOEMGeneral,
2020 static_cast<ipmi_cmd_t>(
2021 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
2022 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08002023
2024 ipmiPrintAndRegister(
2025 netfnIntcOEMGeneral,
2026 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
2027 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
2028
2029 ipmiPrintAndRegister(
2030 netfnIntcOEMGeneral,
2031 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
2032 NULL, ipmiOEMGetFanConfig, PRIVILEGE_USER);
2033
James Feistacc8a4e2019-04-02 14:23:57 -07002034 ipmi::registerHandler(
2035 ipmi::prioOemBase, netfnIntcOEMGeneral,
2036 static_cast<ipmi::Cmd>(
2037 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
2038 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07002039
James Feistacc8a4e2019-04-02 14:23:57 -07002040 ipmi::registerHandler(
2041 ipmi::prioOemBase, netfnIntcOEMGeneral,
2042 static_cast<ipmi::Cmd>(
2043 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
2044 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
2045
2046 ipmi::registerHandler(
2047 ipmi::prioOemBase, netfnIntcOEMGeneral,
2048 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
2049 ipmi::Privilege::User, ipmiOEMSetFscParameter);
2050
2051 ipmi::registerHandler(
2052 ipmi::prioOemBase, netfnIntcOEMGeneral,
2053 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
2054 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07002055
Richard Marian Thomaiyarea537d52019-04-24 21:33:48 +05302056 ipmi::registerHandler(
2057 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
2058 static_cast<ipmi::Cmd>(
2059 IPMINetfnIntelOEMGeneralCmd::cmdReadBaseBoardProductId),
2060 ipmi::Privilege::Admin, ipmiOEMReadBoardProductId);
2061
Kuiying Wang45f04982018-12-26 09:23:08 +08002062 ipmiPrintAndRegister(
2063 netfnIntcOEMGeneral,
2064 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
2065 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08002066 ipmiPrintAndRegister(
2067 netfnIntcOEMPlatform,
2068 static_cast<ipmi_cmd_t>(
2069 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
2070 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Zhu, Yungebe560b02019-04-21 21:19:21 -04002071 ipmi::registerHandler(
2072 ipmi::prioOemBase, netfnIntcOEMGeneral,
2073 static_cast<ipmi::Cmd>(
2074 IPMINetfnIntelOEMGeneralCmd::cmdSetFaultIndication),
2075 ipmi::Privilege::Operator, ipmiOEMSetFaultIndication);
Vernon Mauery4ac799d2019-05-20 15:50:37 -07002076
2077 registerHandler(prioOemBase, netfn::intel::oemGeneral,
2078 netfn::intel::cmdRestoreConfiguration, Privilege::Admin,
2079 ipmiRestoreConfiguration);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08002080}
2081
2082} // namespace ipmi