blob: 80e7ad89814c1242ecb994cbd37ac080bb4ab268 [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>
Jason M. Bills64796042018-10-03 16:51:55 -070026#include <commandutils.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080027#include <iostream>
Jia, Chunhuicc49b542019-03-20 15:41:07 +080028#include <ipmid/api.hpp>
Vernon Mauery5480ef62019-03-20 13:43:11 -070029#include <ipmid/utils.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080030#include <oemcommands.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080031#include <phosphor-logging/log.hpp>
32#include <sdbusplus/bus.hpp>
Suryakanth Sekard509eb92018-11-15 17:44:11 +053033#include <sdbusplus/message/types.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <string>
James Feist91244a62019-02-19 15:04:54 -080035#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080036#include <vector>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080037
38namespace ipmi
39{
Jason M. Bills64796042018-10-03 16:51:55 -070040static void registerOEMFunctions() __attribute__((constructor));
Jason M. Bills6d9c83f2019-02-08 14:02:19 -080041sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
Jason M. Bills64796042018-10-03 16:51:55 -070042static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080043
Suryakanth Sekard509eb92018-11-15 17:44:11 +053044static constexpr auto ethernetIntf =
45 "xyz.openbmc_project.Network.EthernetInterface";
46static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP";
47static constexpr auto networkService = "xyz.openbmc_project.Network";
48static constexpr auto networkRoot = "/xyz/openbmc_project/network";
49
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080050// return code: 0 successful
51int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
52{
53 std::string objpath = "/xyz/openbmc_project/FruDevice";
54 std::string intf = "xyz.openbmc_project.FruDeviceManager";
55 std::string service = getService(bus, intf, objpath);
56 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
57 if (valueTree.empty())
58 {
59 phosphor::logging::log<phosphor::logging::level::ERR>(
60 "No object implements interface",
61 phosphor::logging::entry("INTF=%s", intf.c_str()));
62 return -1;
63 }
64
Jason M. Bills64796042018-10-03 16:51:55 -070065 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080066 {
67 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
68 if (interface == item.second.end())
69 {
70 continue;
71 }
72
73 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
74 if (property == interface->second.end())
75 {
76 continue;
77 }
78
79 try
80 {
81 Value variant = property->second;
Jason M. Bills64796042018-10-03 16:51:55 -070082 std::string& result =
83 sdbusplus::message::variant_ns::get<std::string>(variant);
84 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080085 {
86 phosphor::logging::log<phosphor::logging::level::ERR>(
87 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080088 return -1;
89 }
Jason M. Bills64796042018-10-03 16:51:55 -070090 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080091 return 0;
92 }
Jason M. Bills64796042018-10-03 16:51:55 -070093 catch (sdbusplus::message::variant_ns::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080094 {
Jason M. Bills64796042018-10-03 16:51:55 -070095 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080096 return -1;
97 }
98 }
99 return -1;
100}
Jason M. Bills64796042018-10-03 16:51:55 -0700101
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800102ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
103 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700104 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800105{
Jason M. Bills64796042018-10-03 16:51:55 -0700106 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800107 // Status code.
108 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700109 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800110 return rc;
111}
112
113// Returns the Chassis Identifier (serial #)
114ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
115 ipmi_request_t request,
116 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700117 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800118 ipmi_context_t context)
119{
120 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700121 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800122 {
Jason M. Bills64796042018-10-03 16:51:55 -0700123 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800124 return IPMI_CC_REQ_DATA_LEN_INVALID;
125 }
Jason M. Bills64796042018-10-03 16:51:55 -0700126 if (getChassisSerialNumber(dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800127 {
Jason M. Bills64796042018-10-03 16:51:55 -0700128 *dataLen = serial.size(); // length will never exceed response length
129 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800130 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700131 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800132 return IPMI_CC_OK;
133 }
Jason M. Bills64796042018-10-03 16:51:55 -0700134 *dataLen = 0;
135 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800136}
137
138ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
139 ipmi_request_t request,
140 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700141 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800142{
143 static constexpr size_t safeBufferLength = 50;
144 char buf[safeBufferLength] = {0};
145 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
146
Jason M. Bills64796042018-10-03 16:51:55 -0700147 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800148 {
Jason M. Bills64796042018-10-03 16:51:55 -0700149 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800150 return IPMI_CC_REQ_DATA_LEN_INVALID;
151 }
152
Jason M. Bills64796042018-10-03 16:51:55 -0700153 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154
155 snprintf(
156 buf, safeBufferLength,
157 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
158 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
159 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
160 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
161 Data->node3, Data->node2, Data->node1);
162 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
163 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800164
165 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
166 std::string intf = "xyz.openbmc_project.Common.UUID";
Jason M. Bills64796042018-10-03 16:51:55 -0700167 std::string service = getService(dbus, intf, objpath);
168 setDbusProperty(dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800169 return IPMI_CC_OK;
170}
171
172ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
173 ipmi_request_t request, ipmi_response_t response,
174 ipmi_data_len_t dataLen, ipmi_context_t context)
175{
176 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
177
Jason M. Bills64796042018-10-03 16:51:55 -0700178 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800180 *dataLen = 0;
181 return IPMI_CC_REQ_DATA_LEN_INVALID;
182 }
Jason M. Bills64796042018-10-03 16:51:55 -0700183 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800184
Jason M. Bills64796042018-10-03 16:51:55 -0700185 std::string service = getService(dbus, biosIntf, biosObjPath);
186 setDbusProperty(dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800187 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
188 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700189 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800190 *dataLen = 1;
191 return IPMI_CC_OK;
192}
193
194ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
195 ipmi_request_t request,
196 ipmi_response_t response,
197 ipmi_data_len_t dataLen, ipmi_context_t context)
198{
199 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
200 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
201
202 if (*dataLen == 0)
203 {
Jason M. Bills64796042018-10-03 16:51:55 -0700204 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800205 return IPMI_CC_REQ_DATA_LEN_INVALID;
206 }
207
208 size_t reqDataLen = *dataLen;
209 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700210 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800211 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800212 return IPMI_CC_INVALID_FIELD_REQUEST;
213 }
214
215 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700216 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800217 {
218 case OEMDevEntityType::biosId:
219 {
220 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
221 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800222 return IPMI_CC_REQ_DATA_LEN_INVALID;
223 }
224
Jason M. Bills64796042018-10-03 16:51:55 -0700225 std::string service = getService(dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800226 try
227 {
Jason M. Bills64796042018-10-03 16:51:55 -0700228 Value variant = getDbusProperty(dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800229 biosIntf, biosProp);
Jason M. Bills64796042018-10-03 16:51:55 -0700230 std::string& idString =
231 sdbusplus::message::variant_ns::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800232 if (req->offset >= idString.size())
233 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800234 return IPMI_CC_PARM_OUT_OF_RANGE;
235 }
Jason M. Bills64796042018-10-03 16:51:55 -0700236 size_t length = 0;
237 if (req->countToRead > (idString.size() - req->offset))
238 {
239 length = idString.size() - req->offset;
240 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800241 else
242 {
Jason M. Bills64796042018-10-03 16:51:55 -0700243 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800244 }
Jason M. Bills64796042018-10-03 16:51:55 -0700245 std::copy(idString.begin() + req->offset, idString.end(),
246 res->data);
247 res->resDatalen = length;
248 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800249 }
Jason M. Bills64796042018-10-03 16:51:55 -0700250 catch (sdbusplus::message::variant_ns::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800251 {
Jason M. Bills64796042018-10-03 16:51:55 -0700252 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800253 return IPMI_CC_UNSPECIFIED_ERROR;
254 }
255 }
256 break;
257
258 case OEMDevEntityType::devVer:
259 case OEMDevEntityType::sdrVer:
260 // TODO:
261 return IPMI_CC_ILLEGAL_COMMAND;
262 default:
263 return IPMI_CC_INVALID_FIELD_REQUEST;
264 }
265 return IPMI_CC_OK;
266}
267
268ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
269 ipmi_request_t request, ipmi_response_t response,
270 ipmi_data_len_t dataLen, ipmi_context_t context)
271{
272 if (*dataLen != 0)
273 {
Jason M. Bills64796042018-10-03 16:51:55 -0700274 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800275 return IPMI_CC_REQ_DATA_LEN_INVALID;
276 }
277
278 *dataLen = 1;
279 uint8_t* res = reinterpret_cast<uint8_t*>(response);
280 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
281 // AIC is available so that BIOS will not timeout repeatly which leads to
282 // slow booting.
283 *res = 0; // Byte1=Count of SlotPosition/FruID records.
284 return IPMI_CC_OK;
285}
286
Jason M. Bills64796042018-10-03 16:51:55 -0700287ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
288 ipmi_request_t request,
289 ipmi_response_t response,
290 ipmi_data_len_t dataLen,
291 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800292{
Jason M. Bills64796042018-10-03 16:51:55 -0700293 GetPowerRestoreDelayRes* resp =
294 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
295
296 if (*dataLen != 0)
297 {
298 *dataLen = 0;
299 return IPMI_CC_REQ_DATA_LEN_INVALID;
300 }
301
302 std::string service =
303 getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
304 Value variant =
305 getDbusProperty(dbus, service, powerRestoreDelayObjPath,
306 powerRestoreDelayIntf, powerRestoreDelayProp);
307
308 uint16_t delay = sdbusplus::message::variant_ns::get<uint16_t>(variant);
309 resp->byteLSB = delay;
310 resp->byteMSB = delay >> 8;
311
312 *dataLen = sizeof(GetPowerRestoreDelayRes);
313
314 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800315}
316
Jia, Chunhuicc49b542019-03-20 15:41:07 +0800317static uint8_t bcdToDec(uint8_t val)
318{
319 return ((val / 16 * 10) + (val % 16));
320}
321
322// Allows an update utility or system BIOS to send the status of an embedded
323// firmware update attempt to the BMC. After received, BMC will create a logging
324// record.
325ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target,
326 uint8_t majorRevision,
327 uint8_t minorRevision,
328 uint32_t auxInfo)
329{
330 std::string firmware;
331 target = (target & selEvtTargetMask) >> selEvtTargetShift;
332
333 /* make sure the status is 0, 1, or 2 as per the spec */
334 if (status > 2)
335 {
336 return ipmi::response(ipmi::ccInvalidFieldRequest);
337 }
338 /*orignal OEM command is to record OEM SEL.
339 But openbmc does not support OEM SEL, so we redirect it to redfish event
340 logging. */
341 std::string buildInfo;
342 std::string action;
343 switch (FWUpdateTarget(target))
344 {
345 case FWUpdateTarget::targetBMC:
346 firmware = "BMC";
347 buildInfo = " major: " + std::to_string(majorRevision) +
348 " minor: " +
349 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
350 " BuildID: " + std::to_string(auxInfo);
351 buildInfo += std::to_string(auxInfo);
352 break;
353 case FWUpdateTarget::targetBIOS:
354 firmware = "BIOS";
355 buildInfo =
356 " major: " +
357 std::to_string(bcdToDec(majorRevision)) + // BCD encoded
358 " minor: " +
359 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
360 " ReleaseNumber: " + // ASCII encoded
361 std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') +
362 std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') +
363 std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') +
364 std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0');
365 break;
366 case FWUpdateTarget::targetME:
367 firmware = "ME";
368 buildInfo =
369 " major: " + std::to_string(majorRevision) + " minor1: " +
370 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
371 " minor2: " +
372 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) +
373 " build1: " +
374 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) +
375 " build2: " +
376 std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16)));
377 break;
378 case FWUpdateTarget::targetOEMEWS:
379 firmware = "EWS";
380 buildInfo = " major: " + std::to_string(majorRevision) +
381 " minor: " +
382 std::to_string(bcdToDec(minorRevision)) + // BCD encoded
383 " BuildID: " + std::to_string(auxInfo);
384 break;
385 }
386
387 switch (status)
388 {
389 case 0x0:
390 action = "update started";
391 break;
392 case 0x1:
393 action = "update completed successfully";
394 break;
395 case 0x2:
396 action = "update failure";
397 break;
398 default:
399 action = "unknown";
400 break;
401 }
402
403 std::string message(
404 "[firmware update] " + firmware + " instance: " +
405 std::to_string((target & targetInstanceMask) >> targetInstanceShift) +
406 " status: <" + action + ">" + buildInfo);
407 static constexpr const char* redfishMsgId = "FirmwareUpdate";
408
409 sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO,
410 "REDFISH_MESSAGE_ID=%s", redfishMsgId, NULL);
411 return ipmi::responseSuccess();
412}
413
Jason M. Bills64796042018-10-03 16:51:55 -0700414ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
415 ipmi_request_t request,
416 ipmi_response_t response,
417 ipmi_data_len_t dataLen,
418 ipmi_context_t context)
419{
420 SetPowerRestoreDelayReq* data =
421 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
422 uint16_t delay = 0;
423
424 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
425 {
426 *dataLen = 0;
427 return IPMI_CC_REQ_DATA_LEN_INVALID;
428 }
429 delay = data->byteMSB;
430 delay = (delay << 8) | data->byteLSB;
431 std::string service =
432 getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
433 setDbusProperty(dbus, service, powerRestoreDelayObjPath,
434 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
435 *dataLen = 0;
436
437 return IPMI_CC_OK;
438}
439
440ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
441 ipmi_request_t request,
442 ipmi_response_t response,
443 ipmi_data_len_t dataLen,
444 ipmi_context_t context)
445{
446 GetProcessorErrConfigRes* resp =
447 reinterpret_cast<GetProcessorErrConfigRes*>(response);
448
449 if (*dataLen != 0)
450 {
451 *dataLen = 0;
452 return IPMI_CC_REQ_DATA_LEN_INVALID;
453 }
454
455 std::string service =
456 getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
457 Value variant = getDbusProperty(dbus, service, processorErrConfigObjPath,
458 processorErrConfigIntf, "ResetCfg");
459 resp->resetCfg = sdbusplus::message::variant_ns::get<uint8_t>(variant);
460
461 std::vector<uint8_t> caterrStatus;
Kuiying Wangbc546672018-11-23 15:41:05 +0800462 sdbusplus::message::variant<std::vector<uint8_t>> message;
Jason M. Bills64796042018-10-03 16:51:55 -0700463
464 auto method =
465 dbus.new_method_call(service.c_str(), processorErrConfigObjPath,
466 "org.freedesktop.DBus.Properties", "Get");
467
468 method.append(processorErrConfigIntf, "CATERRStatus");
Kuiying Wangbc546672018-11-23 15:41:05 +0800469 auto reply = dbus.call(method);
Jason M. Bills64796042018-10-03 16:51:55 -0700470
471 try
472 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800473 reply.read(message);
474 caterrStatus =
475 sdbusplus::message::variant_ns::get<std::vector<uint8_t>>(message);
Jason M. Bills64796042018-10-03 16:51:55 -0700476 }
477 catch (sdbusplus::exception_t&)
478 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800479 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills64796042018-10-03 16:51:55 -0700480 "ipmiOEMGetProcessorErrConfig: error on dbus",
481 phosphor::logging::entry("PRORPERTY=CATERRStatus"),
482 phosphor::logging::entry("PATH=%s", processorErrConfigObjPath),
483 phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf));
484 return IPMI_CC_UNSPECIFIED_ERROR;
485 }
486
487 size_t len =
488 maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size();
489 caterrStatus.resize(len);
490 std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus);
491 *dataLen = sizeof(GetProcessorErrConfigRes);
492
493 return IPMI_CC_OK;
494}
495
496ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
497 ipmi_request_t request,
498 ipmi_response_t response,
499 ipmi_data_len_t dataLen,
500 ipmi_context_t context)
501{
502 SetProcessorErrConfigReq* req =
503 reinterpret_cast<SetProcessorErrConfigReq*>(request);
504
505 if (*dataLen != sizeof(SetProcessorErrConfigReq))
506 {
507 *dataLen = 0;
508 return IPMI_CC_REQ_DATA_LEN_INVALID;
509 }
510 std::string service =
511 getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
512 setDbusProperty(dbus, service, processorErrConfigObjPath,
513 processorErrConfigIntf, "ResetCfg", req->resetCfg);
514
515 setDbusProperty(dbus, service, processorErrConfigObjPath,
516 processorErrConfigIntf, "ResetErrorOccurrenceCounts",
517 req->resetErrorOccurrenceCounts);
518 *dataLen = 0;
519
520 return IPMI_CC_OK;
521}
522
Yong Li703922d2018-11-06 13:25:31 +0800523ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
524 ipmi_request_t request,
525 ipmi_response_t response,
526 ipmi_data_len_t dataLen,
527 ipmi_context_t context)
528{
529 GetOEMShutdownPolicyRes* resp =
530 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
531
532 if (*dataLen != 0)
533 {
534 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800535 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800536 *dataLen = 0;
537 return IPMI_CC_REQ_DATA_LEN_INVALID;
538 }
539
540 *dataLen = 0;
541
542 try
543 {
544 std::string service =
545 getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
546 Value variant = getDbusProperty(dbus, service, oemShutdownPolicyObjPath,
547 oemShutdownPolicyIntf,
548 oemShutdownPolicyObjPathProp);
549 resp->policy = sdbusplus::message::variant_ns::get<uint8_t>(variant);
550 // TODO needs to check if it is multi-node products,
551 // policy is only supported on node 3/4
552 resp->policySupport = shutdownPolicySupported;
553 }
554 catch (sdbusplus::exception_t& e)
555 {
556 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
557 return IPMI_CC_UNSPECIFIED_ERROR;
558 }
559
560 *dataLen = sizeof(GetOEMShutdownPolicyRes);
561 return IPMI_CC_OK;
562}
563
564ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
565 ipmi_request_t request,
566 ipmi_response_t response,
567 ipmi_data_len_t dataLen,
568 ipmi_context_t context)
569{
570 uint8_t* req = reinterpret_cast<uint8_t*>(request);
571
572 // TODO needs to check if it is multi-node products,
573 // policy is only supported on node 3/4
574 if (*dataLen != 1)
575 {
576 phosphor::logging::log<phosphor::logging::level::ERR>(
577 "oem_set_shutdown_policy: invalid input len!");
578 *dataLen = 0;
579 return IPMI_CC_REQ_DATA_LEN_INVALID;
580 }
581
582 *dataLen = 0;
583 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
584 {
585 phosphor::logging::log<phosphor::logging::level::ERR>(
586 "oem_set_shutdown_policy: invalid input!");
587 return IPMI_CC_INVALID_FIELD_REQUEST;
588 }
589
590 try
591 {
592 std::string service =
593 getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
594 setDbusProperty(dbus, service, oemShutdownPolicyObjPath,
595 oemShutdownPolicyIntf, oemShutdownPolicyObjPathProp,
596 *req);
597 }
598 catch (sdbusplus::exception_t& e)
599 {
600 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
601 return IPMI_CC_UNSPECIFIED_ERROR;
602 }
603
604 return IPMI_CC_OK;
605}
606
Suryakanth Sekard509eb92018-11-15 17:44:11 +0530607/** @brief implementation for check the DHCP or not in IPv4
608 * @param[in] Channel - Channel number
609 * @returns true or false.
610 */
611static bool isDHCPEnabled(uint8_t Channel)
612{
613 try
614 {
615 auto ethdevice = getChannelName(Channel);
616 if (ethdevice.empty())
617 {
618 return false;
619 }
620 auto ethIP = ethdevice + "/ipv4";
621 auto ethernetObj =
622 getDbusObject(dbus, networkIPIntf, networkRoot, ethIP);
623 auto value = getDbusProperty(dbus, networkService, ethernetObj.first,
624 networkIPIntf, "Origin");
625 if (sdbusplus::message::variant_ns::get<std::string>(value) ==
626 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
627 {
628 return true;
629 }
630 else
631 {
632 return false;
633 }
634 }
635 catch (sdbusplus::exception_t& e)
636 {
637 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
638 return true;
639 }
640}
641
642/** @brief implementes for check the DHCP or not in IPv6
643 * @param[in] Channel - Channel number
644 * @returns true or false.
645 */
646static bool isDHCPIPv6Enabled(uint8_t Channel)
647{
648
649 try
650 {
651 auto ethdevice = getChannelName(Channel);
652 if (ethdevice.empty())
653 {
654 return false;
655 }
656 auto ethIP = ethdevice + "/ipv6";
657 auto objectInfo =
658 getDbusObject(dbus, networkIPIntf, networkRoot, ethIP);
659 auto properties = getAllDbusProperties(dbus, objectInfo.second,
660 objectInfo.first, networkIPIntf);
661 if (sdbusplus::message::variant_ns::get<std::string>(
662 properties["Origin"]) ==
663 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP")
664 {
665 return true;
666 }
667 else
668 {
669 return false;
670 }
671 }
672 catch (sdbusplus::exception_t& e)
673 {
674 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
675 return true;
676 }
677}
678
679/** @brief implementes the creating of default new user
680 * @param[in] userName - new username in 16 bytes.
681 * @param[in] userPassword - new password in 20 bytes
682 * @returns ipmi completion code.
683 */
684ipmi::RspType<> ipmiOEMSetUser2Activation(
685 std::array<uint8_t, ipmi::ipmiMaxUserName>& userName,
686 std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword)
687{
688 bool userState = false;
689 // Check for System Interface not exist and LAN should be static
690 for (uint8_t channel = 0; channel < maxIpmiChannels; channel++)
691 {
692 ChannelInfo chInfo;
693 try
694 {
695 getChannelInfo(channel, chInfo);
696 }
697 catch (sdbusplus::exception_t& e)
698 {
699 phosphor::logging::log<phosphor::logging::level::ERR>(
700 "ipmiOEMSetUser2Activation: Failed to get Channel Info",
701 phosphor::logging::entry("MSG: %s", e.description()));
702 return ipmi::response(ipmi::ccUnspecifiedError);
703 }
704 if (chInfo.mediumType ==
705 static_cast<uint8_t>(EChannelMediumType::systemInterface))
706 {
707 phosphor::logging::log<phosphor::logging::level::ERR>(
708 "ipmiOEMSetUser2Activation: system interface exist .");
709 return ipmi::response(ipmi::ccCommandNotAvailable);
710 }
711 else
712 {
713
714 if (chInfo.mediumType ==
715 static_cast<uint8_t>(EChannelMediumType::lan8032))
716 {
717 if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel))
718 {
719 phosphor::logging::log<phosphor::logging::level::ERR>(
720 "ipmiOEMSetUser2Activation: DHCP enabled .");
721 return ipmi::response(ipmi::ccCommandNotAvailable);
722 }
723 }
724 }
725 }
726 uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0;
727 if (ipmi::ccSuccess ==
728 ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers))
729 {
730 if (enabledUsers > 1)
731 {
732 phosphor::logging::log<phosphor::logging::level::ERR>(
733 "ipmiOEMSetUser2Activation: more than one user is enabled.");
734 return ipmi::response(ipmi::ccCommandNotAvailable);
735 }
736 // Check the user 2 is enabled or not
737 ipmiUserCheckEnabled(ipmiDefaultUserId, userState);
738 if (userState == true)
739 {
740 phosphor::logging::log<phosphor::logging::level::ERR>(
741 "ipmiOEMSetUser2Activation: user 2 already enabled .");
742 return ipmi::response(ipmi::ccCommandNotAvailable);
743 }
744 }
745 else
746 {
747 return ipmi::response(ipmi::ccUnspecifiedError);
748 }
749
750#if BYTE_ORDER == LITTLE_ENDIAN
751 PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0};
752#endif
753#if BYTE_ORDER == BIG_ENDIAN
754 PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN};
755#endif
756
757 if (ipmi::ccSuccess ==
758 ipmiUserSetUserName(ipmiDefaultUserId,
759 reinterpret_cast<const char*>(userName.data())))
760 {
761 if (ipmi::ccSuccess ==
762 ipmiUserSetUserPassword(
763 ipmiDefaultUserId,
764 reinterpret_cast<const char*>(userPassword.data())))
765 {
766 if (ipmi::ccSuccess ==
767 ipmiUserSetPrivilegeAccess(
768 ipmiDefaultUserId,
769 static_cast<uint8_t>(ipmi::EChannelID::chanLan1),
770 privAccess, true))
771 {
772 phosphor::logging::log<phosphor::logging::level::INFO>(
773 "ipmiOEMSetUser2Activation: user created successfully ");
774 return ipmi::responseSuccess();
775 }
776 }
777 // we need to delete the default user id which added in this command as
778 // password / priv setting is failed.
779 ipmiUserSetUserName(ipmiDefaultUserId, "");
780 phosphor::logging::log<phosphor::logging::level::ERR>(
781 "ipmiOEMSetUser2Activation: password / priv setting is failed.");
782 }
783 else
784 {
785 phosphor::logging::log<phosphor::logging::level::ERR>(
786 "ipmiOEMSetUser2Activation: Setting username failed.");
787 }
788
789 return ipmi::response(ipmi::ccCommandNotAvailable);
790}
791
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +0530792/** @brief implementes setting password for special user
793 * @param[in] specialUserIndex
794 * @param[in] userPassword - new password in 20 bytes
795 * @returns ipmi completion code.
796 */
797ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx,
798 uint8_t specialUserIndex,
799 std::vector<uint8_t> userPassword)
800{
801 ChannelInfo chInfo;
802 try
803 {
804 getChannelInfo(ctx->channel, chInfo);
805 }
806 catch (sdbusplus::exception_t& e)
807 {
808 phosphor::logging::log<phosphor::logging::level::ERR>(
809 "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info",
810 phosphor::logging::entry("MSG: %s", e.description()));
811 return ipmi::responseUnspecifiedError();
812 }
813 if (chInfo.mediumType !=
814 static_cast<uint8_t>(EChannelMediumType::systemInterface))
815 {
816 phosphor::logging::log<phosphor::logging::level::ERR>(
817 "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS "
818 "interface");
819 return ipmi::responseCommandNotAvailable();
820 }
821 if (specialUserIndex != 0)
822 {
823 phosphor::logging::log<phosphor::logging::level::ERR>(
824 "ipmiOEMSetSpecialUserPassword: Invalid user account");
825 return ipmi::responseParmOutOfRange();
826 }
827 constexpr uint8_t minPasswordSizeRequired = 6;
828 if (userPassword.size() < minPasswordSizeRequired ||
829 userPassword.size() > ipmi::maxIpmi20PasswordSize)
830 {
831 return ipmi::responseReqDataLenInvalid();
832 }
833 std::string passwd;
834 passwd.assign(reinterpret_cast<const char*>(userPassword.data()),
835 userPassword.size());
836 return ipmi::response(ipmiSetSpecialUserPassword("root", passwd));
837}
838
Kuiying Wang45f04982018-12-26 09:23:08 +0800839namespace ledAction
840{
841using namespace sdbusplus::xyz::openbmc_project::Led::server;
842std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
843 {Physical::Action::Off, 0x00},
844 {Physical::Action::On, 0x10},
845 {Physical::Action::Blink, 0x01}};
846
847std::map<uint8_t, std::string> offsetObjPath = {
848 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
849
850} // namespace ledAction
851
852int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
853 const std::string& objPath, uint8_t& state)
854{
855 try
856 {
857 std::string service = getService(bus, intf, objPath);
858 Value stateValue =
859 getDbusProperty(bus, service, objPath, intf, "State");
860 std::string strState =
861 sdbusplus::message::variant_ns::get<std::string>(stateValue);
862 state = ledAction::actionDbusToIpmi.at(
863 sdbusplus::xyz::openbmc_project::Led::server::Physical::
864 convertActionFromString(strState));
865 }
866 catch (sdbusplus::exception::SdBusError& e)
867 {
868 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
869 return -1;
870 }
871 return 0;
872}
873
874ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
875 ipmi_request_t request, ipmi_response_t response,
876 ipmi_data_len_t dataLen, ipmi_context_t context)
877{
878 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
879 // LED Status
880 //[1:0] = Reserved
881 //[3:2] = Status(Amber)
882 //[5:4] = Status(Green)
883 //[7:6] = System Identify
884 // Status definitions:
885 // 00b = Off
886 // 01b = Blink
887 // 10b = On
888 // 11b = invalid
889 if (*dataLen != 0)
890 {
891 phosphor::logging::log<phosphor::logging::level::ERR>(
892 "oem_get_led_status: invalid input len!");
893 *dataLen = 0;
894 return IPMI_CC_REQ_DATA_LEN_INVALID;
895 }
896
897 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
898 *resp = 0;
899 *dataLen = 0;
900 for (auto it = ledAction::offsetObjPath.begin();
901 it != ledAction::offsetObjPath.end(); ++it)
902 {
903 uint8_t state = 0;
904 if (-1 == getLEDState(dbus, ledIntf, it->second, state))
905 {
906 phosphor::logging::log<phosphor::logging::level::ERR>(
907 "oem_get_led_status: fail to get ID LED status!");
908 return IPMI_CC_UNSPECIFIED_ERROR;
909 }
910 *resp |= state << it->first;
911 }
912
913 *dataLen = sizeof(*resp);
914 return IPMI_CC_OK;
915}
916
Yong Li23737fe2019-02-19 08:49:55 +0800917ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
918 ipmi_request_t request,
919 ipmi_response_t response,
920 ipmi_data_len_t dataLen,
921 ipmi_context_t context)
922{
923 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
924 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
925
926 if (*dataLen == 0)
927 {
928 phosphor::logging::log<phosphor::logging::level::ERR>(
929 "CfgHostSerial: invalid input len!",
930 phosphor::logging::entry("LEN=%d", *dataLen));
931 return IPMI_CC_REQ_DATA_LEN_INVALID;
932 }
933
934 switch (req->command)
935 {
936 case getHostSerialCfgCmd:
937 {
938 if (*dataLen != 1)
939 {
940 phosphor::logging::log<phosphor::logging::level::ERR>(
941 "CfgHostSerial: invalid input len!");
942 *dataLen = 0;
943 return IPMI_CC_REQ_DATA_LEN_INVALID;
944 }
945
946 *dataLen = 0;
947
948 boost::process::ipstream is;
949 std::vector<std::string> data;
950 std::string line;
951 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
952 boost::process::std_out > is);
953
954 while (c1.running() && std::getline(is, line) && !line.empty())
955 {
956 data.push_back(line);
957 }
958
959 c1.wait();
960 if (c1.exit_code())
961 {
962 phosphor::logging::log<phosphor::logging::level::ERR>(
963 "CfgHostSerial:: error on execute",
964 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
965 // Using the default value
966 *resp = 0;
967 }
968 else
969 {
970 if (data.size() != 1)
971 {
972 phosphor::logging::log<phosphor::logging::level::ERR>(
973 "CfgHostSerial:: error on read env");
974 return IPMI_CC_UNSPECIFIED_ERROR;
975 }
976 try
977 {
978 unsigned long tmp = std::stoul(data[0]);
979 if (tmp > std::numeric_limits<uint8_t>::max())
980 {
981 throw std::out_of_range("Out of range");
982 }
983 *resp = static_cast<uint8_t>(tmp);
984 }
985 catch (const std::invalid_argument& e)
986 {
987 phosphor::logging::log<phosphor::logging::level::ERR>(
988 "invalid config ",
989 phosphor::logging::entry("ERR=%s", e.what()));
990 return IPMI_CC_UNSPECIFIED_ERROR;
991 }
992 catch (const std::out_of_range& e)
993 {
994 phosphor::logging::log<phosphor::logging::level::ERR>(
995 "out_of_range config ",
996 phosphor::logging::entry("ERR=%s", e.what()));
997 return IPMI_CC_UNSPECIFIED_ERROR;
998 }
999 }
1000
1001 *dataLen = 1;
1002 break;
1003 }
1004 case setHostSerialCfgCmd:
1005 {
1006 if (*dataLen != sizeof(CfgHostSerialReq))
1007 {
1008 phosphor::logging::log<phosphor::logging::level::ERR>(
1009 "CfgHostSerial: invalid input len!");
1010 *dataLen = 0;
1011 return IPMI_CC_REQ_DATA_LEN_INVALID;
1012 }
1013
1014 *dataLen = 0;
1015
1016 if (req->parameter > HostSerialCfgParamMax)
1017 {
1018 phosphor::logging::log<phosphor::logging::level::ERR>(
1019 "CfgHostSerial: invalid input!");
1020 return IPMI_CC_INVALID_FIELD_REQUEST;
1021 }
1022
1023 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
1024 std::to_string(req->parameter));
1025
1026 c1.wait();
1027 if (c1.exit_code())
1028 {
1029 phosphor::logging::log<phosphor::logging::level::ERR>(
1030 "CfgHostSerial:: error on execute",
1031 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
1032 return IPMI_CC_UNSPECIFIED_ERROR;
1033 }
1034 break;
1035 }
1036 default:
1037 phosphor::logging::log<phosphor::logging::level::ERR>(
1038 "CfgHostSerial: invalid input!");
1039 *dataLen = 0;
1040 return IPMI_CC_INVALID_FIELD_REQUEST;
1041 }
1042
1043 return IPMI_CC_OK;
1044}
1045
James Feist91244a62019-02-19 15:04:54 -08001046constexpr const char* thermalModeInterface =
1047 "xyz.openbmc_project.Control.ThermalMode";
1048constexpr const char* thermalModePath =
1049 "/xyz/openbmc_project/control/thermal_mode";
1050
1051bool getFanProfileInterface(
1052 sdbusplus::bus::bus& bus,
1053 boost::container::flat_map<
1054 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1055{
1056 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1057 "GetAll");
1058 call.append(thermalModeInterface);
1059 try
1060 {
1061 auto data = bus.call(call);
1062 data.read(resp);
1063 }
1064 catch (sdbusplus::exception_t& e)
1065 {
1066 phosphor::logging::log<phosphor::logging::level::ERR>(
1067 "getFanProfileInterface: can't get thermal mode!",
1068 phosphor::logging::entry("ERR=%s", e.what()));
1069 return false;
1070 }
1071 return true;
1072}
1073
1074ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1075 ipmi_request_t request, ipmi_response_t response,
1076 ipmi_data_len_t dataLen, ipmi_context_t context)
1077{
1078
1079 if (*dataLen < 2 || *dataLen > 7)
1080 {
1081 phosphor::logging::log<phosphor::logging::level::ERR>(
1082 "ipmiOEMSetFanConfig: invalid input len!");
1083 *dataLen = 0;
1084 return IPMI_CC_REQ_DATA_LEN_INVALID;
1085 }
1086
1087 // todo: tell bios to only send first 2 bytes
1088
1089 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1090 boost::container::flat_map<
1091 std::string, std::variant<std::vector<std::string>, std::string>>
1092 profileData;
1093 if (!getFanProfileInterface(dbus, profileData))
1094 {
1095 return IPMI_CC_UNSPECIFIED_ERROR;
1096 }
1097
1098 std::vector<std::string>* supported =
1099 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1100 if (supported == nullptr)
1101 {
1102 return IPMI_CC_INVALID_FIELD_REQUEST;
1103 }
1104 std::string mode;
1105 if (req->flags &
1106 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1107 {
1108 bool performanceMode =
1109 (req->flags & (1 << static_cast<uint8_t>(
1110 setFanProfileFlags::performAcousSelect))) > 0;
1111
1112 if (performanceMode)
1113 {
1114
1115 if (std::find(supported->begin(), supported->end(),
1116 "Performance") != supported->end())
1117 {
1118 mode = "Performance";
1119 }
1120 }
1121 else
1122 {
1123
1124 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1125 supported->end())
1126 {
1127 mode = "Acoustic";
1128 }
1129 }
1130 if (mode.empty())
1131 {
1132 return IPMI_CC_INVALID_FIELD_REQUEST;
1133 }
1134 setDbusProperty(dbus, settingsBusName, thermalModePath,
1135 thermalModeInterface, "Current", mode);
1136 }
1137
1138 return IPMI_CC_OK;
1139}
1140
1141ipmi_ret_t ipmiOEMGetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1142 ipmi_request_t request, ipmi_response_t response,
1143 ipmi_data_len_t dataLen, ipmi_context_t context)
1144{
1145
1146 if (*dataLen > 1)
1147 {
1148 phosphor::logging::log<phosphor::logging::level::ERR>(
1149 "ipmiOEMGetFanConfig: invalid input len!");
1150 *dataLen = 0;
1151 return IPMI_CC_REQ_DATA_LEN_INVALID;
1152 }
1153
1154 // todo: talk to bios about needing less information
1155
1156 GetFanConfigResp* resp = reinterpret_cast<GetFanConfigResp*>(response);
1157 *dataLen = sizeof(GetFanConfigResp);
1158
1159 boost::container::flat_map<
1160 std::string, std::variant<std::vector<std::string>, std::string>>
1161 profileData;
1162
1163 if (!getFanProfileInterface(dbus, profileData))
1164 {
1165 return IPMI_CC_UNSPECIFIED_ERROR;
1166 }
1167
1168 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1169
1170 if (current == nullptr)
1171 {
1172 phosphor::logging::log<phosphor::logging::level::ERR>(
1173 "ipmiOEMGetFanConfig: can't get current mode!");
1174 return IPMI_CC_UNSPECIFIED_ERROR;
1175 }
1176 bool performance = (*current == "Performance");
1177
1178 if (performance)
1179 {
1180 resp->flags |= 1 << 2;
1181 }
1182
1183 return IPMI_CC_OK;
1184}
1185
James Feist5f957ca2019-03-14 15:33:55 -07001186constexpr const char* cfmLimitSettingPath =
1187 "/xyz/openbmc_project/control/cfm_limit";
1188constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001189constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feistacc8a4e2019-04-02 14:23:57 -07001190constexpr const char* pidConfigurationIface =
1191 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001192
1193static std::string getExitAirConfigPath()
1194{
1195
1196 auto method =
1197 dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
1198 "/xyz/openbmc_project/object_mapper",
1199 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1200
James Feistacc8a4e2019-04-02 14:23:57 -07001201 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001202 std::string path;
1203 GetSubTreeType resp;
1204 try
1205 {
1206 auto reply = dbus.call(method);
1207 reply.read(resp);
1208 }
1209 catch (sdbusplus::exception_t&)
1210 {
1211 phosphor::logging::log<phosphor::logging::level::ERR>(
1212 "ipmiOEMGetFscParameter: mapper error");
1213 };
1214 auto config = std::find_if(resp.begin(), resp.end(), [](const auto& pair) {
1215 return pair.first.find("Exit_Air") != std::string::npos;
1216 });
1217 if (config != resp.end())
1218 {
1219 path = std::move(config->first);
1220 }
1221 return path;
1222}
James Feist5f957ca2019-03-14 15:33:55 -07001223
James Feistacc8a4e2019-04-02 14:23:57 -07001224// flat map to make alphabetical
1225static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1226{
1227 boost::container::flat_map<std::string, PropertyMap> ret;
1228 auto method =
1229 dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
1230 "/xyz/openbmc_project/object_mapper",
1231 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1232
1233 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1234 GetSubTreeType resp;
1235
1236 try
1237 {
1238 auto reply = dbus.call(method);
1239 reply.read(resp);
1240 }
1241 catch (sdbusplus::exception_t&)
1242 {
1243 phosphor::logging::log<phosphor::logging::level::ERR>(
1244 "getFanConfigPaths: mapper error");
1245 };
1246 for (const auto& [path, objects] : resp)
1247 {
1248 if (objects.empty())
1249 {
1250 continue; // should be impossible
1251 }
1252 ret.emplace(path, getAllDbusProperties(dbus, objects[0].first, path,
1253 pidConfigurationIface));
1254 }
1255 return ret;
1256}
1257
1258ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1259{
1260 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1261 if (data.empty())
1262 {
1263 return ipmi::responseResponseError();
1264 }
1265 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1266 for (const auto& [_, pid] : data)
1267 {
1268 auto findClass = pid.find("Class");
1269 if (findClass == pid.end())
1270 {
1271 phosphor::logging::log<phosphor::logging::level::ERR>(
1272 "ipmiOEMGetFscParameter: found illegal pid "
1273 "configurations");
1274 return ipmi::responseResponseError();
1275 }
1276 std::string type = std::get<std::string>(findClass->second);
1277 if (type == "fan")
1278 {
1279 auto findOutLimit = pid.find("OutLimitMin");
1280 if (findOutLimit == pid.end())
1281 {
1282 phosphor::logging::log<phosphor::logging::level::ERR>(
1283 "ipmiOEMGetFscParameter: found illegal pid "
1284 "configurations");
1285 return ipmi::responseResponseError();
1286 }
1287 // get the min out of all the offsets
1288 minOffset = std::min(
1289 minOffset,
1290 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1291 }
1292 }
1293 if (minOffset == std::numeric_limits<uint8_t>::max())
1294 {
1295 phosphor::logging::log<phosphor::logging::level::ERR>(
1296 "ipmiOEMGetFscParameter: found no fan configurations!");
1297 return ipmi::responseResponseError();
1298 }
1299
1300 return ipmi::responseSuccess(minOffset);
1301}
1302
1303ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1304{
1305 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1306 if (data.empty())
1307 {
1308
1309 phosphor::logging::log<phosphor::logging::level::ERR>(
1310 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1311 return ipmi::responseResponseError();
1312 }
1313
1314 bool found = false;
1315 for (const auto& [path, pid] : data)
1316 {
1317 auto findClass = pid.find("Class");
1318 if (findClass == pid.end())
1319 {
1320
1321 phosphor::logging::log<phosphor::logging::level::ERR>(
1322 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1323 "configurations");
1324 return ipmi::responseResponseError();
1325 }
1326 std::string type = std::get<std::string>(findClass->second);
1327 if (type == "fan")
1328 {
1329 auto findOutLimit = pid.find("OutLimitMin");
1330 if (findOutLimit == pid.end())
1331 {
1332
1333 phosphor::logging::log<phosphor::logging::level::ERR>(
1334 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1335 "configurations");
1336 return ipmi::responseResponseError();
1337 }
1338 ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
1339 path, pidConfigurationIface, "OutLimitMin",
1340 static_cast<double>(offset));
1341 found = true;
1342 }
1343 }
1344 if (!found)
1345 {
1346 phosphor::logging::log<phosphor::logging::level::ERR>(
1347 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1348 return ipmi::responseResponseError();
1349 }
1350
1351 return ipmi::responseSuccess();
1352}
1353
1354ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1355 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001356{
1357 constexpr const size_t disableLimiting = 0x0;
1358
James Feistacc8a4e2019-04-02 14:23:57 -07001359 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001360 {
James Feistacc8a4e2019-04-02 14:23:57 -07001361 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001362 {
James Feistfaa4f222019-03-21 16:21:55 -07001363 std::string path = getExitAirConfigPath();
1364 ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001365 path, pidConfigurationIface, "SetPoint",
1366 static_cast<double>(param2));
1367 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001368 }
1369 else
1370 {
James Feistacc8a4e2019-04-02 14:23:57 -07001371 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001372 }
1373 }
James Feistacc8a4e2019-04-02 14:23:57 -07001374 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001375 {
James Feistacc8a4e2019-04-02 14:23:57 -07001376 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001377
1378 // must be greater than 50 based on eps
1379 if (cfm < 50 && cfm != disableLimiting)
1380 {
James Feistacc8a4e2019-04-02 14:23:57 -07001381 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001382 }
1383
1384 try
1385 {
1386 ipmi::setDbusProperty(dbus, settingsBusName, cfmLimitSettingPath,
1387 cfmLimitIface, "Limit",
1388 static_cast<double>(cfm));
1389 }
1390 catch (sdbusplus::exception_t& e)
1391 {
1392 phosphor::logging::log<phosphor::logging::level::ERR>(
1393 "ipmiOEMSetFscParameter: can't set cfm setting!",
1394 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001395 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001396 }
James Feistacc8a4e2019-04-02 14:23:57 -07001397 return ipmi::responseSuccess();
1398 }
1399 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1400 {
1401 constexpr const size_t maxDomainCount = 8;
1402 uint8_t requestedDomainMask = param1;
1403 boost::container::flat_map data = getPidConfigs();
1404 if (data.empty())
1405 {
1406
1407 phosphor::logging::log<phosphor::logging::level::ERR>(
1408 "ipmiOEMSetFscParameter: found no pid configurations!");
1409 return ipmi::responseResponseError();
1410 }
1411 size_t count = 0;
1412 for (const auto& [path, pid] : data)
1413 {
1414 auto findClass = pid.find("Class");
1415 if (findClass == pid.end())
1416 {
1417
1418 phosphor::logging::log<phosphor::logging::level::ERR>(
1419 "ipmiOEMSetFscParameter: found illegal pid "
1420 "configurations");
1421 return ipmi::responseResponseError();
1422 }
1423 std::string type = std::get<std::string>(findClass->second);
1424 if (type == "fan")
1425 {
1426 if (requestedDomainMask & (1 << count))
1427 {
1428 ipmi::setDbusProperty(
1429 dbus, "xyz.openbmc_project.EntityManager", path,
1430 pidConfigurationIface, "OutLimitMax",
1431 static_cast<double>(param2));
1432 }
1433 count++;
1434 }
1435 }
1436 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001437 }
1438 else
1439 {
1440 // todo other command parts possibly
1441 // tcontrol is handled in peci now
1442 // fan speed offset not implemented yet
1443 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001444 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001445 }
1446}
1447
James Feistacc8a4e2019-04-02 14:23:57 -07001448ipmi::RspType<
1449 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1450 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001451{
James Feistfaa4f222019-03-21 16:21:55 -07001452 constexpr uint8_t legacyDefaultExitAirLimit = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001453
James Feistacc8a4e2019-04-02 14:23:57 -07001454 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001455 {
James Feistacc8a4e2019-04-02 14:23:57 -07001456 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001457 {
James Feistacc8a4e2019-04-02 14:23:57 -07001458 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001459 }
1460
James Feistacc8a4e2019-04-02 14:23:57 -07001461 if (*param != legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001462 {
James Feistacc8a4e2019-04-02 14:23:57 -07001463 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001464 }
1465 uint8_t setpoint = legacyDefaultExitAirLimit;
1466 std::string path = getExitAirConfigPath();
1467 if (path.size())
1468 {
James Feistacc8a4e2019-04-02 14:23:57 -07001469 Value val =
1470 ipmi::getDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
1471 path, pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001472 setpoint = std::floor(std::get<double>(val) + 0.5);
1473 }
1474
1475 // old implementation used to return the "default" and current, we
1476 // don't make the default readily available so just make both the
1477 // same
James Feistfaa4f222019-03-21 16:21:55 -07001478
James Feistacc8a4e2019-04-02 14:23:57 -07001479 return ipmi::responseSuccess(
1480 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001481 }
James Feistacc8a4e2019-04-02 14:23:57 -07001482 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1483 {
1484 constexpr const size_t maxDomainCount = 8;
1485
1486 if (!param)
1487 {
1488 return ipmi::responseReqDataLenInvalid();
1489 }
1490 uint8_t requestedDomain = *param;
1491 if (requestedDomain >= maxDomainCount)
1492 {
1493 return ipmi::responseInvalidFieldRequest();
1494 }
1495
1496 boost::container::flat_map data = getPidConfigs();
1497 if (data.empty())
1498 {
1499 phosphor::logging::log<phosphor::logging::level::ERR>(
1500 "ipmiOEMGetFscParameter: found no pid configurations!");
1501 return ipmi::responseResponseError();
1502 }
1503 size_t count = 0;
1504 for (const auto& [_, pid] : data)
1505 {
1506 auto findClass = pid.find("Class");
1507 if (findClass == pid.end())
1508 {
1509 phosphor::logging::log<phosphor::logging::level::ERR>(
1510 "ipmiOEMGetFscParameter: found illegal pid "
1511 "configurations");
1512 return ipmi::responseResponseError();
1513 }
1514 std::string type = std::get<std::string>(findClass->second);
1515 if (type == "fan")
1516 {
1517 if (requestedDomain == count)
1518 {
1519 auto findOutLimit = pid.find("OutLimitMax");
1520 if (findOutLimit == pid.end())
1521 {
1522 phosphor::logging::log<phosphor::logging::level::ERR>(
1523 "ipmiOEMGetFscParameter: found illegal pid "
1524 "configurations");
1525 return ipmi::responseResponseError();
1526 }
1527
1528 return ipmi::responseSuccess(
1529 static_cast<uint8_t>(std::floor(
1530 std::get<double>(findOutLimit->second) + 0.5)));
1531 }
1532 else
1533 {
1534 count++;
1535 }
1536 }
1537 }
1538
1539 return ipmi::responseInvalidFieldRequest();
1540 }
1541 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001542 {
1543
1544 /*
1545 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001546 previous behavior didn't seem to prevent this, ignore the check for
1547 now.
James Feist5f957ca2019-03-14 15:33:55 -07001548
James Feistacc8a4e2019-04-02 14:23:57 -07001549 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001550 {
1551 phosphor::logging::log<phosphor::logging::level::ERR>(
1552 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001553 return IPMI_CC_REQ_DATA_LEN_INVALID;
1554 }
1555 */
1556 Value cfmLimit;
1557 Value cfmMaximum;
1558 try
1559 {
1560 cfmLimit = ipmi::getDbusProperty(dbus, settingsBusName,
1561 cfmLimitSettingPath, cfmLimitIface,
1562 "Limit");
1563 cfmMaximum = ipmi::getDbusProperty(
1564 dbus, "xyz.openbmc_project.ExitAirTempSensor",
1565 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1566 }
1567 catch (sdbusplus::exception_t& e)
1568 {
1569 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001570 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001571 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001572 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001573 }
1574
James Feistacc8a4e2019-04-02 14:23:57 -07001575 double cfmMax = std::get<double>(cfmMaximum);
1576 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001577
James Feistacc8a4e2019-04-02 14:23:57 -07001578 cfmLim = std::floor(cfmLim + 0.5);
1579 cfmMax = std::floor(cfmMax + 0.5);
1580 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1581 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001582
James Feistacc8a4e2019-04-02 14:23:57 -07001583 return ipmi::responseSuccess(
1584 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001585 }
James Feistacc8a4e2019-04-02 14:23:57 -07001586
James Feist5f957ca2019-03-14 15:33:55 -07001587 else
1588 {
1589 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001590 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001591 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001592 }
1593}
1594
Jason M. Bills64796042018-10-03 16:51:55 -07001595static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001596{
1597 phosphor::logging::log<phosphor::logging::level::INFO>(
1598 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07001599 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
1600 ipmiOEMWildcard,
1601 PRIVILEGE_USER); // wildcard default handler
1602 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
1603 ipmiOEMWildcard,
1604 PRIVILEGE_USER); // wildcard default handler
1605 ipmiPrintAndRegister(
1606 netfnIntcOEMGeneral,
1607 static_cast<ipmi_cmd_t>(
1608 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
1609 NULL, ipmiOEMGetChassisIdentifier,
1610 PRIVILEGE_USER); // get chassis identifier
1611 ipmiPrintAndRegister(
1612 netfnIntcOEMGeneral,
1613 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
1614 NULL, ipmiOEMSetSystemGUID,
1615 PRIVILEGE_ADMIN); // set system guid
1616 ipmiPrintAndRegister(
1617 netfnIntcOEMGeneral,
1618 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
1619 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
1620 ipmiPrintAndRegister(netfnIntcOEMGeneral,
1621 static_cast<ipmi_cmd_t>(
1622 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
1623 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
1624 ipmiPrintAndRegister(
1625 netfnIntcOEMGeneral,
1626 static_cast<ipmi_cmd_t>(
1627 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
1628 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08001629
1630 ipmi::registerHandler(
1631 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1632 static_cast<ipmi::Cmd>(
1633 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
1634 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
1635
Jason M. Bills64796042018-10-03 16:51:55 -07001636 ipmiPrintAndRegister(
1637 netfnIntcOEMGeneral,
1638 static_cast<ipmi_cmd_t>(
1639 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
1640 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
1641 ipmiPrintAndRegister(
1642 netfnIntcOEMGeneral,
1643 static_cast<ipmi_cmd_t>(
1644 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
1645 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301646
1647 ipmi::registerHandler(
1648 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1649 static_cast<ipmi::Cmd>(
1650 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
1651 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
1652
Richard Marian Thomaiyarfc5e9852019-04-14 15:06:27 +05301653 ipmi::registerHandler(
1654 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1655 static_cast<ipmi::Cmd>(
1656 IPMINetfnIntelOEMGeneralCmd::cmdSetSpecialUserPassword),
1657 ipmi::Privilege::Callback, ipmiOEMSetSpecialUserPassword);
1658
Jason M. Bills64796042018-10-03 16:51:55 -07001659 ipmiPrintAndRegister(
1660 netfnIntcOEMGeneral,
1661 static_cast<ipmi_cmd_t>(
1662 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
1663 NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
1664 ipmiPrintAndRegister(
1665 netfnIntcOEMGeneral,
1666 static_cast<ipmi_cmd_t>(
1667 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
1668 NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
Yong Li703922d2018-11-06 13:25:31 +08001669 ipmiPrintAndRegister(netfnIntcOEMGeneral,
1670 static_cast<ipmi_cmd_t>(
1671 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
1672 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
1673 ipmiPrintAndRegister(netfnIntcOEMGeneral,
1674 static_cast<ipmi_cmd_t>(
1675 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
1676 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08001677
1678 ipmiPrintAndRegister(
1679 netfnIntcOEMGeneral,
1680 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
1681 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
1682
1683 ipmiPrintAndRegister(
1684 netfnIntcOEMGeneral,
1685 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
1686 NULL, ipmiOEMGetFanConfig, PRIVILEGE_USER);
1687
James Feistacc8a4e2019-04-02 14:23:57 -07001688 ipmi::registerHandler(
1689 ipmi::prioOemBase, netfnIntcOEMGeneral,
1690 static_cast<ipmi::Cmd>(
1691 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
1692 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07001693
James Feistacc8a4e2019-04-02 14:23:57 -07001694 ipmi::registerHandler(
1695 ipmi::prioOemBase, netfnIntcOEMGeneral,
1696 static_cast<ipmi::Cmd>(
1697 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
1698 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
1699
1700 ipmi::registerHandler(
1701 ipmi::prioOemBase, netfnIntcOEMGeneral,
1702 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
1703 ipmi::Privilege::User, ipmiOEMSetFscParameter);
1704
1705 ipmi::registerHandler(
1706 ipmi::prioOemBase, netfnIntcOEMGeneral,
1707 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
1708 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07001709
Kuiying Wang45f04982018-12-26 09:23:08 +08001710 ipmiPrintAndRegister(
1711 netfnIntcOEMGeneral,
1712 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
1713 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08001714 ipmiPrintAndRegister(
1715 netfnIntcOEMPlatform,
1716 static_cast<ipmi_cmd_t>(
1717 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
1718 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001719 return;
1720}
1721
1722} // namespace ipmi