blob: 789678662c8cef8fdda35323789fdff340376c55 [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
Kuiying Wang45f04982018-12-26 09:23:08 +0800792namespace ledAction
793{
794using namespace sdbusplus::xyz::openbmc_project::Led::server;
795std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
796 {Physical::Action::Off, 0x00},
797 {Physical::Action::On, 0x10},
798 {Physical::Action::Blink, 0x01}};
799
800std::map<uint8_t, std::string> offsetObjPath = {
801 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
802
803} // namespace ledAction
804
805int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
806 const std::string& objPath, uint8_t& state)
807{
808 try
809 {
810 std::string service = getService(bus, intf, objPath);
811 Value stateValue =
812 getDbusProperty(bus, service, objPath, intf, "State");
813 std::string strState =
814 sdbusplus::message::variant_ns::get<std::string>(stateValue);
815 state = ledAction::actionDbusToIpmi.at(
816 sdbusplus::xyz::openbmc_project::Led::server::Physical::
817 convertActionFromString(strState));
818 }
819 catch (sdbusplus::exception::SdBusError& e)
820 {
821 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
822 return -1;
823 }
824 return 0;
825}
826
827ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
828 ipmi_request_t request, ipmi_response_t response,
829 ipmi_data_len_t dataLen, ipmi_context_t context)
830{
831 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
832 // LED Status
833 //[1:0] = Reserved
834 //[3:2] = Status(Amber)
835 //[5:4] = Status(Green)
836 //[7:6] = System Identify
837 // Status definitions:
838 // 00b = Off
839 // 01b = Blink
840 // 10b = On
841 // 11b = invalid
842 if (*dataLen != 0)
843 {
844 phosphor::logging::log<phosphor::logging::level::ERR>(
845 "oem_get_led_status: invalid input len!");
846 *dataLen = 0;
847 return IPMI_CC_REQ_DATA_LEN_INVALID;
848 }
849
850 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
851 *resp = 0;
852 *dataLen = 0;
853 for (auto it = ledAction::offsetObjPath.begin();
854 it != ledAction::offsetObjPath.end(); ++it)
855 {
856 uint8_t state = 0;
857 if (-1 == getLEDState(dbus, ledIntf, it->second, state))
858 {
859 phosphor::logging::log<phosphor::logging::level::ERR>(
860 "oem_get_led_status: fail to get ID LED status!");
861 return IPMI_CC_UNSPECIFIED_ERROR;
862 }
863 *resp |= state << it->first;
864 }
865
866 *dataLen = sizeof(*resp);
867 return IPMI_CC_OK;
868}
869
Yong Li23737fe2019-02-19 08:49:55 +0800870ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
871 ipmi_request_t request,
872 ipmi_response_t response,
873 ipmi_data_len_t dataLen,
874 ipmi_context_t context)
875{
876 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
877 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
878
879 if (*dataLen == 0)
880 {
881 phosphor::logging::log<phosphor::logging::level::ERR>(
882 "CfgHostSerial: invalid input len!",
883 phosphor::logging::entry("LEN=%d", *dataLen));
884 return IPMI_CC_REQ_DATA_LEN_INVALID;
885 }
886
887 switch (req->command)
888 {
889 case getHostSerialCfgCmd:
890 {
891 if (*dataLen != 1)
892 {
893 phosphor::logging::log<phosphor::logging::level::ERR>(
894 "CfgHostSerial: invalid input len!");
895 *dataLen = 0;
896 return IPMI_CC_REQ_DATA_LEN_INVALID;
897 }
898
899 *dataLen = 0;
900
901 boost::process::ipstream is;
902 std::vector<std::string> data;
903 std::string line;
904 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
905 boost::process::std_out > is);
906
907 while (c1.running() && std::getline(is, line) && !line.empty())
908 {
909 data.push_back(line);
910 }
911
912 c1.wait();
913 if (c1.exit_code())
914 {
915 phosphor::logging::log<phosphor::logging::level::ERR>(
916 "CfgHostSerial:: error on execute",
917 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
918 // Using the default value
919 *resp = 0;
920 }
921 else
922 {
923 if (data.size() != 1)
924 {
925 phosphor::logging::log<phosphor::logging::level::ERR>(
926 "CfgHostSerial:: error on read env");
927 return IPMI_CC_UNSPECIFIED_ERROR;
928 }
929 try
930 {
931 unsigned long tmp = std::stoul(data[0]);
932 if (tmp > std::numeric_limits<uint8_t>::max())
933 {
934 throw std::out_of_range("Out of range");
935 }
936 *resp = static_cast<uint8_t>(tmp);
937 }
938 catch (const std::invalid_argument& e)
939 {
940 phosphor::logging::log<phosphor::logging::level::ERR>(
941 "invalid config ",
942 phosphor::logging::entry("ERR=%s", e.what()));
943 return IPMI_CC_UNSPECIFIED_ERROR;
944 }
945 catch (const std::out_of_range& e)
946 {
947 phosphor::logging::log<phosphor::logging::level::ERR>(
948 "out_of_range config ",
949 phosphor::logging::entry("ERR=%s", e.what()));
950 return IPMI_CC_UNSPECIFIED_ERROR;
951 }
952 }
953
954 *dataLen = 1;
955 break;
956 }
957 case setHostSerialCfgCmd:
958 {
959 if (*dataLen != sizeof(CfgHostSerialReq))
960 {
961 phosphor::logging::log<phosphor::logging::level::ERR>(
962 "CfgHostSerial: invalid input len!");
963 *dataLen = 0;
964 return IPMI_CC_REQ_DATA_LEN_INVALID;
965 }
966
967 *dataLen = 0;
968
969 if (req->parameter > HostSerialCfgParamMax)
970 {
971 phosphor::logging::log<phosphor::logging::level::ERR>(
972 "CfgHostSerial: invalid input!");
973 return IPMI_CC_INVALID_FIELD_REQUEST;
974 }
975
976 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
977 std::to_string(req->parameter));
978
979 c1.wait();
980 if (c1.exit_code())
981 {
982 phosphor::logging::log<phosphor::logging::level::ERR>(
983 "CfgHostSerial:: error on execute",
984 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
985 return IPMI_CC_UNSPECIFIED_ERROR;
986 }
987 break;
988 }
989 default:
990 phosphor::logging::log<phosphor::logging::level::ERR>(
991 "CfgHostSerial: invalid input!");
992 *dataLen = 0;
993 return IPMI_CC_INVALID_FIELD_REQUEST;
994 }
995
996 return IPMI_CC_OK;
997}
998
James Feist91244a62019-02-19 15:04:54 -0800999constexpr const char* thermalModeInterface =
1000 "xyz.openbmc_project.Control.ThermalMode";
1001constexpr const char* thermalModePath =
1002 "/xyz/openbmc_project/control/thermal_mode";
1003
1004bool getFanProfileInterface(
1005 sdbusplus::bus::bus& bus,
1006 boost::container::flat_map<
1007 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
1008{
1009 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
1010 "GetAll");
1011 call.append(thermalModeInterface);
1012 try
1013 {
1014 auto data = bus.call(call);
1015 data.read(resp);
1016 }
1017 catch (sdbusplus::exception_t& e)
1018 {
1019 phosphor::logging::log<phosphor::logging::level::ERR>(
1020 "getFanProfileInterface: can't get thermal mode!",
1021 phosphor::logging::entry("ERR=%s", e.what()));
1022 return false;
1023 }
1024 return true;
1025}
1026
1027ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1028 ipmi_request_t request, ipmi_response_t response,
1029 ipmi_data_len_t dataLen, ipmi_context_t context)
1030{
1031
1032 if (*dataLen < 2 || *dataLen > 7)
1033 {
1034 phosphor::logging::log<phosphor::logging::level::ERR>(
1035 "ipmiOEMSetFanConfig: invalid input len!");
1036 *dataLen = 0;
1037 return IPMI_CC_REQ_DATA_LEN_INVALID;
1038 }
1039
1040 // todo: tell bios to only send first 2 bytes
1041
1042 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
1043 boost::container::flat_map<
1044 std::string, std::variant<std::vector<std::string>, std::string>>
1045 profileData;
1046 if (!getFanProfileInterface(dbus, profileData))
1047 {
1048 return IPMI_CC_UNSPECIFIED_ERROR;
1049 }
1050
1051 std::vector<std::string>* supported =
1052 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
1053 if (supported == nullptr)
1054 {
1055 return IPMI_CC_INVALID_FIELD_REQUEST;
1056 }
1057 std::string mode;
1058 if (req->flags &
1059 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
1060 {
1061 bool performanceMode =
1062 (req->flags & (1 << static_cast<uint8_t>(
1063 setFanProfileFlags::performAcousSelect))) > 0;
1064
1065 if (performanceMode)
1066 {
1067
1068 if (std::find(supported->begin(), supported->end(),
1069 "Performance") != supported->end())
1070 {
1071 mode = "Performance";
1072 }
1073 }
1074 else
1075 {
1076
1077 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
1078 supported->end())
1079 {
1080 mode = "Acoustic";
1081 }
1082 }
1083 if (mode.empty())
1084 {
1085 return IPMI_CC_INVALID_FIELD_REQUEST;
1086 }
1087 setDbusProperty(dbus, settingsBusName, thermalModePath,
1088 thermalModeInterface, "Current", mode);
1089 }
1090
1091 return IPMI_CC_OK;
1092}
1093
1094ipmi_ret_t ipmiOEMGetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1095 ipmi_request_t request, ipmi_response_t response,
1096 ipmi_data_len_t dataLen, ipmi_context_t context)
1097{
1098
1099 if (*dataLen > 1)
1100 {
1101 phosphor::logging::log<phosphor::logging::level::ERR>(
1102 "ipmiOEMGetFanConfig: invalid input len!");
1103 *dataLen = 0;
1104 return IPMI_CC_REQ_DATA_LEN_INVALID;
1105 }
1106
1107 // todo: talk to bios about needing less information
1108
1109 GetFanConfigResp* resp = reinterpret_cast<GetFanConfigResp*>(response);
1110 *dataLen = sizeof(GetFanConfigResp);
1111
1112 boost::container::flat_map<
1113 std::string, std::variant<std::vector<std::string>, std::string>>
1114 profileData;
1115
1116 if (!getFanProfileInterface(dbus, profileData))
1117 {
1118 return IPMI_CC_UNSPECIFIED_ERROR;
1119 }
1120
1121 std::string* current = std::get_if<std::string>(&profileData["Current"]);
1122
1123 if (current == nullptr)
1124 {
1125 phosphor::logging::log<phosphor::logging::level::ERR>(
1126 "ipmiOEMGetFanConfig: can't get current mode!");
1127 return IPMI_CC_UNSPECIFIED_ERROR;
1128 }
1129 bool performance = (*current == "Performance");
1130
1131 if (performance)
1132 {
1133 resp->flags |= 1 << 2;
1134 }
1135
1136 return IPMI_CC_OK;
1137}
1138
James Feist5f957ca2019-03-14 15:33:55 -07001139constexpr const char* cfmLimitSettingPath =
1140 "/xyz/openbmc_project/control/cfm_limit";
1141constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit";
James Feistfaa4f222019-03-21 16:21:55 -07001142constexpr const size_t legacyExitAirSensorNumber = 0x2e;
James Feistacc8a4e2019-04-02 14:23:57 -07001143constexpr const char* pidConfigurationIface =
1144 "xyz.openbmc_project.Configuration.Pid";
James Feistfaa4f222019-03-21 16:21:55 -07001145
1146static std::string getExitAirConfigPath()
1147{
1148
1149 auto method =
1150 dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
1151 "/xyz/openbmc_project/object_mapper",
1152 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1153
James Feistacc8a4e2019-04-02 14:23:57 -07001154 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
James Feistfaa4f222019-03-21 16:21:55 -07001155 std::string path;
1156 GetSubTreeType resp;
1157 try
1158 {
1159 auto reply = dbus.call(method);
1160 reply.read(resp);
1161 }
1162 catch (sdbusplus::exception_t&)
1163 {
1164 phosphor::logging::log<phosphor::logging::level::ERR>(
1165 "ipmiOEMGetFscParameter: mapper error");
1166 };
1167 auto config = std::find_if(resp.begin(), resp.end(), [](const auto& pair) {
1168 return pair.first.find("Exit_Air") != std::string::npos;
1169 });
1170 if (config != resp.end())
1171 {
1172 path = std::move(config->first);
1173 }
1174 return path;
1175}
James Feist5f957ca2019-03-14 15:33:55 -07001176
James Feistacc8a4e2019-04-02 14:23:57 -07001177// flat map to make alphabetical
1178static boost::container::flat_map<std::string, PropertyMap> getPidConfigs()
1179{
1180 boost::container::flat_map<std::string, PropertyMap> ret;
1181 auto method =
1182 dbus.new_method_call("xyz.openbmc_project.ObjectMapper",
1183 "/xyz/openbmc_project/object_mapper",
1184 "xyz.openbmc_project.ObjectMapper", "GetSubTree");
1185
1186 method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface});
1187 GetSubTreeType resp;
1188
1189 try
1190 {
1191 auto reply = dbus.call(method);
1192 reply.read(resp);
1193 }
1194 catch (sdbusplus::exception_t&)
1195 {
1196 phosphor::logging::log<phosphor::logging::level::ERR>(
1197 "getFanConfigPaths: mapper error");
1198 };
1199 for (const auto& [path, objects] : resp)
1200 {
1201 if (objects.empty())
1202 {
1203 continue; // should be impossible
1204 }
1205 ret.emplace(path, getAllDbusProperties(dbus, objects[0].first, path,
1206 pidConfigurationIface));
1207 }
1208 return ret;
1209}
1210
1211ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void)
1212{
1213 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1214 if (data.empty())
1215 {
1216 return ipmi::responseResponseError();
1217 }
1218 uint8_t minOffset = std::numeric_limits<uint8_t>::max();
1219 for (const auto& [_, pid] : data)
1220 {
1221 auto findClass = pid.find("Class");
1222 if (findClass == pid.end())
1223 {
1224 phosphor::logging::log<phosphor::logging::level::ERR>(
1225 "ipmiOEMGetFscParameter: found illegal pid "
1226 "configurations");
1227 return ipmi::responseResponseError();
1228 }
1229 std::string type = std::get<std::string>(findClass->second);
1230 if (type == "fan")
1231 {
1232 auto findOutLimit = pid.find("OutLimitMin");
1233 if (findOutLimit == pid.end())
1234 {
1235 phosphor::logging::log<phosphor::logging::level::ERR>(
1236 "ipmiOEMGetFscParameter: found illegal pid "
1237 "configurations");
1238 return ipmi::responseResponseError();
1239 }
1240 // get the min out of all the offsets
1241 minOffset = std::min(
1242 minOffset,
1243 static_cast<uint8_t>(std::get<double>(findOutLimit->second)));
1244 }
1245 }
1246 if (minOffset == std::numeric_limits<uint8_t>::max())
1247 {
1248 phosphor::logging::log<phosphor::logging::level::ERR>(
1249 "ipmiOEMGetFscParameter: found no fan configurations!");
1250 return ipmi::responseResponseError();
1251 }
1252
1253 return ipmi::responseSuccess(minOffset);
1254}
1255
1256ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset)
1257{
1258 boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs();
1259 if (data.empty())
1260 {
1261
1262 phosphor::logging::log<phosphor::logging::level::ERR>(
1263 "ipmiOEMSetFanSpeedOffset: found no pid configurations!");
1264 return ipmi::responseResponseError();
1265 }
1266
1267 bool found = false;
1268 for (const auto& [path, pid] : data)
1269 {
1270 auto findClass = pid.find("Class");
1271 if (findClass == pid.end())
1272 {
1273
1274 phosphor::logging::log<phosphor::logging::level::ERR>(
1275 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1276 "configurations");
1277 return ipmi::responseResponseError();
1278 }
1279 std::string type = std::get<std::string>(findClass->second);
1280 if (type == "fan")
1281 {
1282 auto findOutLimit = pid.find("OutLimitMin");
1283 if (findOutLimit == pid.end())
1284 {
1285
1286 phosphor::logging::log<phosphor::logging::level::ERR>(
1287 "ipmiOEMSetFanSpeedOffset: found illegal pid "
1288 "configurations");
1289 return ipmi::responseResponseError();
1290 }
1291 ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
1292 path, pidConfigurationIface, "OutLimitMin",
1293 static_cast<double>(offset));
1294 found = true;
1295 }
1296 }
1297 if (!found)
1298 {
1299 phosphor::logging::log<phosphor::logging::level::ERR>(
1300 "ipmiOEMSetFanSpeedOffset: set no fan offsets");
1301 return ipmi::responseResponseError();
1302 }
1303
1304 return ipmi::responseSuccess();
1305}
1306
1307ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1,
1308 uint8_t param2)
James Feist5f957ca2019-03-14 15:33:55 -07001309{
1310 constexpr const size_t disableLimiting = 0x0;
1311
James Feistacc8a4e2019-04-02 14:23:57 -07001312 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001313 {
James Feistacc8a4e2019-04-02 14:23:57 -07001314 if (param1 == legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001315 {
James Feistfaa4f222019-03-21 16:21:55 -07001316 std::string path = getExitAirConfigPath();
1317 ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
James Feistacc8a4e2019-04-02 14:23:57 -07001318 path, pidConfigurationIface, "SetPoint",
1319 static_cast<double>(param2));
1320 return ipmi::responseSuccess();
James Feistfaa4f222019-03-21 16:21:55 -07001321 }
1322 else
1323 {
James Feistacc8a4e2019-04-02 14:23:57 -07001324 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001325 }
1326 }
James Feistacc8a4e2019-04-02 14:23:57 -07001327 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001328 {
James Feistacc8a4e2019-04-02 14:23:57 -07001329 uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8);
James Feist5f957ca2019-03-14 15:33:55 -07001330
1331 // must be greater than 50 based on eps
1332 if (cfm < 50 && cfm != disableLimiting)
1333 {
James Feistacc8a4e2019-04-02 14:23:57 -07001334 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001335 }
1336
1337 try
1338 {
1339 ipmi::setDbusProperty(dbus, settingsBusName, cfmLimitSettingPath,
1340 cfmLimitIface, "Limit",
1341 static_cast<double>(cfm));
1342 }
1343 catch (sdbusplus::exception_t& e)
1344 {
1345 phosphor::logging::log<phosphor::logging::level::ERR>(
1346 "ipmiOEMSetFscParameter: can't set cfm setting!",
1347 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001348 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001349 }
James Feistacc8a4e2019-04-02 14:23:57 -07001350 return ipmi::responseSuccess();
1351 }
1352 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1353 {
1354 constexpr const size_t maxDomainCount = 8;
1355 uint8_t requestedDomainMask = param1;
1356 boost::container::flat_map data = getPidConfigs();
1357 if (data.empty())
1358 {
1359
1360 phosphor::logging::log<phosphor::logging::level::ERR>(
1361 "ipmiOEMSetFscParameter: found no pid configurations!");
1362 return ipmi::responseResponseError();
1363 }
1364 size_t count = 0;
1365 for (const auto& [path, pid] : data)
1366 {
1367 auto findClass = pid.find("Class");
1368 if (findClass == pid.end())
1369 {
1370
1371 phosphor::logging::log<phosphor::logging::level::ERR>(
1372 "ipmiOEMSetFscParameter: found illegal pid "
1373 "configurations");
1374 return ipmi::responseResponseError();
1375 }
1376 std::string type = std::get<std::string>(findClass->second);
1377 if (type == "fan")
1378 {
1379 if (requestedDomainMask & (1 << count))
1380 {
1381 ipmi::setDbusProperty(
1382 dbus, "xyz.openbmc_project.EntityManager", path,
1383 pidConfigurationIface, "OutLimitMax",
1384 static_cast<double>(param2));
1385 }
1386 count++;
1387 }
1388 }
1389 return ipmi::responseSuccess();
James Feist5f957ca2019-03-14 15:33:55 -07001390 }
1391 else
1392 {
1393 // todo other command parts possibly
1394 // tcontrol is handled in peci now
1395 // fan speed offset not implemented yet
1396 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001397 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001398 }
1399}
1400
James Feistacc8a4e2019-04-02 14:23:57 -07001401ipmi::RspType<
1402 std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>>
1403 ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param)
James Feist5f957ca2019-03-14 15:33:55 -07001404{
James Feistfaa4f222019-03-21 16:21:55 -07001405 constexpr uint8_t legacyDefaultExitAirLimit = -128;
James Feist5f957ca2019-03-14 15:33:55 -07001406
James Feistacc8a4e2019-04-02 14:23:57 -07001407 if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol))
James Feist5f957ca2019-03-14 15:33:55 -07001408 {
James Feistacc8a4e2019-04-02 14:23:57 -07001409 if (!param)
James Feistfaa4f222019-03-21 16:21:55 -07001410 {
James Feistacc8a4e2019-04-02 14:23:57 -07001411 return ipmi::responseReqDataLenInvalid();
James Feistfaa4f222019-03-21 16:21:55 -07001412 }
1413
James Feistacc8a4e2019-04-02 14:23:57 -07001414 if (*param != legacyExitAirSensorNumber)
James Feistfaa4f222019-03-21 16:21:55 -07001415 {
James Feistacc8a4e2019-04-02 14:23:57 -07001416 return ipmi::responseParmOutOfRange();
James Feistfaa4f222019-03-21 16:21:55 -07001417 }
1418 uint8_t setpoint = legacyDefaultExitAirLimit;
1419 std::string path = getExitAirConfigPath();
1420 if (path.size())
1421 {
James Feistacc8a4e2019-04-02 14:23:57 -07001422 Value val =
1423 ipmi::getDbusProperty(dbus, "xyz.openbmc_project.EntityManager",
1424 path, pidConfigurationIface, "SetPoint");
James Feistfaa4f222019-03-21 16:21:55 -07001425 setpoint = std::floor(std::get<double>(val) + 0.5);
1426 }
1427
1428 // old implementation used to return the "default" and current, we
1429 // don't make the default readily available so just make both the
1430 // same
James Feistfaa4f222019-03-21 16:21:55 -07001431
James Feistacc8a4e2019-04-02 14:23:57 -07001432 return ipmi::responseSuccess(
1433 std::array<uint8_t, 2>{setpoint, setpoint});
James Feistfaa4f222019-03-21 16:21:55 -07001434 }
James Feistacc8a4e2019-04-02 14:23:57 -07001435 else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm))
1436 {
1437 constexpr const size_t maxDomainCount = 8;
1438
1439 if (!param)
1440 {
1441 return ipmi::responseReqDataLenInvalid();
1442 }
1443 uint8_t requestedDomain = *param;
1444 if (requestedDomain >= maxDomainCount)
1445 {
1446 return ipmi::responseInvalidFieldRequest();
1447 }
1448
1449 boost::container::flat_map data = getPidConfigs();
1450 if (data.empty())
1451 {
1452 phosphor::logging::log<phosphor::logging::level::ERR>(
1453 "ipmiOEMGetFscParameter: found no pid configurations!");
1454 return ipmi::responseResponseError();
1455 }
1456 size_t count = 0;
1457 for (const auto& [_, pid] : data)
1458 {
1459 auto findClass = pid.find("Class");
1460 if (findClass == pid.end())
1461 {
1462 phosphor::logging::log<phosphor::logging::level::ERR>(
1463 "ipmiOEMGetFscParameter: found illegal pid "
1464 "configurations");
1465 return ipmi::responseResponseError();
1466 }
1467 std::string type = std::get<std::string>(findClass->second);
1468 if (type == "fan")
1469 {
1470 if (requestedDomain == count)
1471 {
1472 auto findOutLimit = pid.find("OutLimitMax");
1473 if (findOutLimit == pid.end())
1474 {
1475 phosphor::logging::log<phosphor::logging::level::ERR>(
1476 "ipmiOEMGetFscParameter: found illegal pid "
1477 "configurations");
1478 return ipmi::responseResponseError();
1479 }
1480
1481 return ipmi::responseSuccess(
1482 static_cast<uint8_t>(std::floor(
1483 std::get<double>(findOutLimit->second) + 0.5)));
1484 }
1485 else
1486 {
1487 count++;
1488 }
1489 }
1490 }
1491
1492 return ipmi::responseInvalidFieldRequest();
1493 }
1494 else if (command == static_cast<uint8_t>(setFscParamFlags::cfm))
James Feist5f957ca2019-03-14 15:33:55 -07001495 {
1496
1497 /*
1498 DataLen should be 1, but host is sending us an extra bit. As the
James Feistacc8a4e2019-04-02 14:23:57 -07001499 previous behavior didn't seem to prevent this, ignore the check for
1500 now.
James Feist5f957ca2019-03-14 15:33:55 -07001501
James Feistacc8a4e2019-04-02 14:23:57 -07001502 if (param)
James Feist5f957ca2019-03-14 15:33:55 -07001503 {
1504 phosphor::logging::log<phosphor::logging::level::ERR>(
1505 "ipmiOEMGetFscParameter: invalid input len!");
James Feist5f957ca2019-03-14 15:33:55 -07001506 return IPMI_CC_REQ_DATA_LEN_INVALID;
1507 }
1508 */
1509 Value cfmLimit;
1510 Value cfmMaximum;
1511 try
1512 {
1513 cfmLimit = ipmi::getDbusProperty(dbus, settingsBusName,
1514 cfmLimitSettingPath, cfmLimitIface,
1515 "Limit");
1516 cfmMaximum = ipmi::getDbusProperty(
1517 dbus, "xyz.openbmc_project.ExitAirTempSensor",
1518 "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit");
1519 }
1520 catch (sdbusplus::exception_t& e)
1521 {
1522 phosphor::logging::log<phosphor::logging::level::ERR>(
James Feistacc8a4e2019-04-02 14:23:57 -07001523 "ipmiOEMGetFscParameter: can't get cfm setting!",
James Feist5f957ca2019-03-14 15:33:55 -07001524 phosphor::logging::entry("ERR=%s", e.what()));
James Feistacc8a4e2019-04-02 14:23:57 -07001525 return ipmi::responseResponseError();
James Feist5f957ca2019-03-14 15:33:55 -07001526 }
1527
James Feistacc8a4e2019-04-02 14:23:57 -07001528 double cfmMax = std::get<double>(cfmMaximum);
1529 double cfmLim = std::get<double>(cfmLimit);
James Feist5f957ca2019-03-14 15:33:55 -07001530
James Feistacc8a4e2019-04-02 14:23:57 -07001531 cfmLim = std::floor(cfmLim + 0.5);
1532 cfmMax = std::floor(cfmMax + 0.5);
1533 uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim);
1534 uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax);
James Feist5f957ca2019-03-14 15:33:55 -07001535
James Feistacc8a4e2019-04-02 14:23:57 -07001536 return ipmi::responseSuccess(
1537 std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp});
James Feist5f957ca2019-03-14 15:33:55 -07001538 }
James Feistacc8a4e2019-04-02 14:23:57 -07001539
James Feist5f957ca2019-03-14 15:33:55 -07001540 else
1541 {
1542 // todo other command parts possibly
James Feist5f957ca2019-03-14 15:33:55 -07001543 // domain pwm limit not implemented
James Feistacc8a4e2019-04-02 14:23:57 -07001544 return ipmi::responseParmOutOfRange();
James Feist5f957ca2019-03-14 15:33:55 -07001545 }
1546}
1547
Jason M. Bills64796042018-10-03 16:51:55 -07001548static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001549{
1550 phosphor::logging::log<phosphor::logging::level::INFO>(
1551 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -07001552 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
1553 ipmiOEMWildcard,
1554 PRIVILEGE_USER); // wildcard default handler
1555 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
1556 ipmiOEMWildcard,
1557 PRIVILEGE_USER); // wildcard default handler
1558 ipmiPrintAndRegister(
1559 netfnIntcOEMGeneral,
1560 static_cast<ipmi_cmd_t>(
1561 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
1562 NULL, ipmiOEMGetChassisIdentifier,
1563 PRIVILEGE_USER); // get chassis identifier
1564 ipmiPrintAndRegister(
1565 netfnIntcOEMGeneral,
1566 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
1567 NULL, ipmiOEMSetSystemGUID,
1568 PRIVILEGE_ADMIN); // set system guid
1569 ipmiPrintAndRegister(
1570 netfnIntcOEMGeneral,
1571 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
1572 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
1573 ipmiPrintAndRegister(netfnIntcOEMGeneral,
1574 static_cast<ipmi_cmd_t>(
1575 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
1576 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
1577 ipmiPrintAndRegister(
1578 netfnIntcOEMGeneral,
1579 static_cast<ipmi_cmd_t>(
1580 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
1581 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
Jia, Chunhuicc49b542019-03-20 15:41:07 +08001582
1583 ipmi::registerHandler(
1584 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1585 static_cast<ipmi::Cmd>(
1586 IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus),
1587 ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus);
1588
Jason M. Bills64796042018-10-03 16:51:55 -07001589 ipmiPrintAndRegister(
1590 netfnIntcOEMGeneral,
1591 static_cast<ipmi_cmd_t>(
1592 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
1593 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
1594 ipmiPrintAndRegister(
1595 netfnIntcOEMGeneral,
1596 static_cast<ipmi_cmd_t>(
1597 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
1598 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
Suryakanth Sekard509eb92018-11-15 17:44:11 +05301599
1600 ipmi::registerHandler(
1601 ipmi::prioOpenBmcBase, ipmi::netFnOemOne,
1602 static_cast<ipmi::Cmd>(
1603 IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation),
1604 ipmi::Privilege::Callback, ipmiOEMSetUser2Activation);
1605
Jason M. Bills64796042018-10-03 16:51:55 -07001606 ipmiPrintAndRegister(
1607 netfnIntcOEMGeneral,
1608 static_cast<ipmi_cmd_t>(
1609 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
1610 NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
1611 ipmiPrintAndRegister(
1612 netfnIntcOEMGeneral,
1613 static_cast<ipmi_cmd_t>(
1614 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
1615 NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
Yong Li703922d2018-11-06 13:25:31 +08001616 ipmiPrintAndRegister(netfnIntcOEMGeneral,
1617 static_cast<ipmi_cmd_t>(
1618 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
1619 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
1620 ipmiPrintAndRegister(netfnIntcOEMGeneral,
1621 static_cast<ipmi_cmd_t>(
1622 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
1623 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -08001624
1625 ipmiPrintAndRegister(
1626 netfnIntcOEMGeneral,
1627 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
1628 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
1629
1630 ipmiPrintAndRegister(
1631 netfnIntcOEMGeneral,
1632 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
1633 NULL, ipmiOEMGetFanConfig, PRIVILEGE_USER);
1634
James Feistacc8a4e2019-04-02 14:23:57 -07001635 ipmi::registerHandler(
1636 ipmi::prioOemBase, netfnIntcOEMGeneral,
1637 static_cast<ipmi::Cmd>(
1638 IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset),
1639 ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset);
James Feist5f957ca2019-03-14 15:33:55 -07001640
James Feistacc8a4e2019-04-02 14:23:57 -07001641 ipmi::registerHandler(
1642 ipmi::prioOemBase, netfnIntcOEMGeneral,
1643 static_cast<ipmi::Cmd>(
1644 IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset),
1645 ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset);
1646
1647 ipmi::registerHandler(
1648 ipmi::prioOemBase, netfnIntcOEMGeneral,
1649 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter),
1650 ipmi::Privilege::User, ipmiOEMSetFscParameter);
1651
1652 ipmi::registerHandler(
1653 ipmi::prioOemBase, netfnIntcOEMGeneral,
1654 static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter),
1655 ipmi::Privilege::User, ipmiOEMGetFscParameter);
James Feist5f957ca2019-03-14 15:33:55 -07001656
Kuiying Wang45f04982018-12-26 09:23:08 +08001657 ipmiPrintAndRegister(
1658 netfnIntcOEMGeneral,
1659 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
1660 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +08001661 ipmiPrintAndRegister(
1662 netfnIntcOEMPlatform,
1663 static_cast<ipmi_cmd_t>(
1664 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
1665 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +08001666 return;
1667}
1668
1669} // namespace ipmi