blob: 5791b281b846dc548a619cab7bda0817703af9bc [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
Jason M. Bills6d9c83f2019-02-08 14:02:19 -080020#include <ipmid/api.h>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080021
22#include <array>
Yong Li23737fe2019-02-19 08:49:55 +080023#include <boost/process/child.hpp>
24#include <boost/process/io.hpp>
Jason M. Bills64796042018-10-03 16:51:55 -070025#include <commandutils.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080026#include <iostream>
27#include <oemcommands.hpp>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070028#include <phosphor-ipmi-host/utils.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080029#include <phosphor-logging/log.hpp>
30#include <sdbusplus/bus.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080031#include <string>
32#include <vector>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080033
34namespace ipmi
35{
Jason M. Bills64796042018-10-03 16:51:55 -070036static void registerOEMFunctions() __attribute__((constructor));
Jason M. Bills6d9c83f2019-02-08 14:02:19 -080037sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
Jason M. Bills64796042018-10-03 16:51:55 -070038static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080039
40// return code: 0 successful
41int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
42{
43 std::string objpath = "/xyz/openbmc_project/FruDevice";
44 std::string intf = "xyz.openbmc_project.FruDeviceManager";
45 std::string service = getService(bus, intf, objpath);
46 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
47 if (valueTree.empty())
48 {
49 phosphor::logging::log<phosphor::logging::level::ERR>(
50 "No object implements interface",
51 phosphor::logging::entry("INTF=%s", intf.c_str()));
52 return -1;
53 }
54
Jason M. Bills64796042018-10-03 16:51:55 -070055 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080056 {
57 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
58 if (interface == item.second.end())
59 {
60 continue;
61 }
62
63 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
64 if (property == interface->second.end())
65 {
66 continue;
67 }
68
69 try
70 {
71 Value variant = property->second;
Jason M. Bills64796042018-10-03 16:51:55 -070072 std::string& result =
73 sdbusplus::message::variant_ns::get<std::string>(variant);
74 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080075 {
76 phosphor::logging::log<phosphor::logging::level::ERR>(
77 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080078 return -1;
79 }
Jason M. Bills64796042018-10-03 16:51:55 -070080 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080081 return 0;
82 }
Jason M. Bills64796042018-10-03 16:51:55 -070083 catch (sdbusplus::message::variant_ns::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080084 {
Jason M. Bills64796042018-10-03 16:51:55 -070085 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080086 return -1;
87 }
88 }
89 return -1;
90}
Jason M. Bills64796042018-10-03 16:51:55 -070091
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080092ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
93 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -070094 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080095{
Jason M. Bills64796042018-10-03 16:51:55 -070096 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080097 // Status code.
98 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -070099 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800100 return rc;
101}
102
103// Returns the Chassis Identifier (serial #)
104ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
105 ipmi_request_t request,
106 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700107 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800108 ipmi_context_t context)
109{
110 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700111 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800112 {
Jason M. Bills64796042018-10-03 16:51:55 -0700113 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800114 return IPMI_CC_REQ_DATA_LEN_INVALID;
115 }
Jason M. Bills64796042018-10-03 16:51:55 -0700116 if (getChassisSerialNumber(dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800117 {
Jason M. Bills64796042018-10-03 16:51:55 -0700118 *dataLen = serial.size(); // length will never exceed response length
119 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800120 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700121 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800122 return IPMI_CC_OK;
123 }
Jason M. Bills64796042018-10-03 16:51:55 -0700124 *dataLen = 0;
125 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800126}
127
128ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
129 ipmi_request_t request,
130 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700131 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800132{
133 static constexpr size_t safeBufferLength = 50;
134 char buf[safeBufferLength] = {0};
135 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
136
Jason M. Bills64796042018-10-03 16:51:55 -0700137 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800138 {
Jason M. Bills64796042018-10-03 16:51:55 -0700139 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800140 return IPMI_CC_REQ_DATA_LEN_INVALID;
141 }
142
Jason M. Bills64796042018-10-03 16:51:55 -0700143 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800144
145 snprintf(
146 buf, safeBufferLength,
147 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
148 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
149 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
150 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
151 Data->node3, Data->node2, Data->node1);
152 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
153 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800154
155 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
156 std::string intf = "xyz.openbmc_project.Common.UUID";
Jason M. Bills64796042018-10-03 16:51:55 -0700157 std::string service = getService(dbus, intf, objpath);
158 setDbusProperty(dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800159 return IPMI_CC_OK;
160}
161
162ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
163 ipmi_request_t request, ipmi_response_t response,
164 ipmi_data_len_t dataLen, ipmi_context_t context)
165{
166 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
167
Jason M. Bills64796042018-10-03 16:51:55 -0700168 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800169 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800170 *dataLen = 0;
171 return IPMI_CC_REQ_DATA_LEN_INVALID;
172 }
Jason M. Bills64796042018-10-03 16:51:55 -0700173 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800174
Jason M. Bills64796042018-10-03 16:51:55 -0700175 std::string service = getService(dbus, biosIntf, biosObjPath);
176 setDbusProperty(dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800177 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
178 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700179 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800180 *dataLen = 1;
181 return IPMI_CC_OK;
182}
183
184ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
185 ipmi_request_t request,
186 ipmi_response_t response,
187 ipmi_data_len_t dataLen, ipmi_context_t context)
188{
189 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
190 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
191
192 if (*dataLen == 0)
193 {
Jason M. Bills64796042018-10-03 16:51:55 -0700194 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800195 return IPMI_CC_REQ_DATA_LEN_INVALID;
196 }
197
198 size_t reqDataLen = *dataLen;
199 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700200 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800201 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800202 return IPMI_CC_INVALID_FIELD_REQUEST;
203 }
204
205 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700206 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800207 {
208 case OEMDevEntityType::biosId:
209 {
210 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
211 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800212 return IPMI_CC_REQ_DATA_LEN_INVALID;
213 }
214
Jason M. Bills64796042018-10-03 16:51:55 -0700215 std::string service = getService(dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800216 try
217 {
Jason M. Bills64796042018-10-03 16:51:55 -0700218 Value variant = getDbusProperty(dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800219 biosIntf, biosProp);
Jason M. Bills64796042018-10-03 16:51:55 -0700220 std::string& idString =
221 sdbusplus::message::variant_ns::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800222 if (req->offset >= idString.size())
223 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800224 return IPMI_CC_PARM_OUT_OF_RANGE;
225 }
Jason M. Bills64796042018-10-03 16:51:55 -0700226 size_t length = 0;
227 if (req->countToRead > (idString.size() - req->offset))
228 {
229 length = idString.size() - req->offset;
230 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800231 else
232 {
Jason M. Bills64796042018-10-03 16:51:55 -0700233 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800234 }
Jason M. Bills64796042018-10-03 16:51:55 -0700235 std::copy(idString.begin() + req->offset, idString.end(),
236 res->data);
237 res->resDatalen = length;
238 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800239 }
Jason M. Bills64796042018-10-03 16:51:55 -0700240 catch (sdbusplus::message::variant_ns::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800241 {
Jason M. Bills64796042018-10-03 16:51:55 -0700242 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800243 return IPMI_CC_UNSPECIFIED_ERROR;
244 }
245 }
246 break;
247
248 case OEMDevEntityType::devVer:
249 case OEMDevEntityType::sdrVer:
250 // TODO:
251 return IPMI_CC_ILLEGAL_COMMAND;
252 default:
253 return IPMI_CC_INVALID_FIELD_REQUEST;
254 }
255 return IPMI_CC_OK;
256}
257
258ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
259 ipmi_request_t request, ipmi_response_t response,
260 ipmi_data_len_t dataLen, ipmi_context_t context)
261{
262 if (*dataLen != 0)
263 {
Jason M. Bills64796042018-10-03 16:51:55 -0700264 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800265 return IPMI_CC_REQ_DATA_LEN_INVALID;
266 }
267
268 *dataLen = 1;
269 uint8_t* res = reinterpret_cast<uint8_t*>(response);
270 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
271 // AIC is available so that BIOS will not timeout repeatly which leads to
272 // slow booting.
273 *res = 0; // Byte1=Count of SlotPosition/FruID records.
274 return IPMI_CC_OK;
275}
276
Jason M. Bills64796042018-10-03 16:51:55 -0700277ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
278 ipmi_request_t request,
279 ipmi_response_t response,
280 ipmi_data_len_t dataLen,
281 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800282{
Jason M. Bills64796042018-10-03 16:51:55 -0700283 GetPowerRestoreDelayRes* resp =
284 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
285
286 if (*dataLen != 0)
287 {
288 *dataLen = 0;
289 return IPMI_CC_REQ_DATA_LEN_INVALID;
290 }
291
292 std::string service =
293 getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
294 Value variant =
295 getDbusProperty(dbus, service, powerRestoreDelayObjPath,
296 powerRestoreDelayIntf, powerRestoreDelayProp);
297
298 uint16_t delay = sdbusplus::message::variant_ns::get<uint16_t>(variant);
299 resp->byteLSB = delay;
300 resp->byteMSB = delay >> 8;
301
302 *dataLen = sizeof(GetPowerRestoreDelayRes);
303
304 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800305}
306
Jason M. Bills64796042018-10-03 16:51:55 -0700307ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
308 ipmi_request_t request,
309 ipmi_response_t response,
310 ipmi_data_len_t dataLen,
311 ipmi_context_t context)
312{
313 SetPowerRestoreDelayReq* data =
314 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
315 uint16_t delay = 0;
316
317 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
318 {
319 *dataLen = 0;
320 return IPMI_CC_REQ_DATA_LEN_INVALID;
321 }
322 delay = data->byteMSB;
323 delay = (delay << 8) | data->byteLSB;
324 std::string service =
325 getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
326 setDbusProperty(dbus, service, powerRestoreDelayObjPath,
327 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
328 *dataLen = 0;
329
330 return IPMI_CC_OK;
331}
332
333ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
334 ipmi_request_t request,
335 ipmi_response_t response,
336 ipmi_data_len_t dataLen,
337 ipmi_context_t context)
338{
339 GetProcessorErrConfigRes* resp =
340 reinterpret_cast<GetProcessorErrConfigRes*>(response);
341
342 if (*dataLen != 0)
343 {
344 *dataLen = 0;
345 return IPMI_CC_REQ_DATA_LEN_INVALID;
346 }
347
348 std::string service =
349 getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
350 Value variant = getDbusProperty(dbus, service, processorErrConfigObjPath,
351 processorErrConfigIntf, "ResetCfg");
352 resp->resetCfg = sdbusplus::message::variant_ns::get<uint8_t>(variant);
353
354 std::vector<uint8_t> caterrStatus;
Kuiying Wangbc546672018-11-23 15:41:05 +0800355 sdbusplus::message::variant<std::vector<uint8_t>> message;
Jason M. Bills64796042018-10-03 16:51:55 -0700356
357 auto method =
358 dbus.new_method_call(service.c_str(), processorErrConfigObjPath,
359 "org.freedesktop.DBus.Properties", "Get");
360
361 method.append(processorErrConfigIntf, "CATERRStatus");
Kuiying Wangbc546672018-11-23 15:41:05 +0800362 auto reply = dbus.call(method);
Jason M. Bills64796042018-10-03 16:51:55 -0700363
364 try
365 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800366 reply.read(message);
367 caterrStatus =
368 sdbusplus::message::variant_ns::get<std::vector<uint8_t>>(message);
Jason M. Bills64796042018-10-03 16:51:55 -0700369 }
370 catch (sdbusplus::exception_t&)
371 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800372 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills64796042018-10-03 16:51:55 -0700373 "ipmiOEMGetProcessorErrConfig: error on dbus",
374 phosphor::logging::entry("PRORPERTY=CATERRStatus"),
375 phosphor::logging::entry("PATH=%s", processorErrConfigObjPath),
376 phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf));
377 return IPMI_CC_UNSPECIFIED_ERROR;
378 }
379
380 size_t len =
381 maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size();
382 caterrStatus.resize(len);
383 std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus);
384 *dataLen = sizeof(GetProcessorErrConfigRes);
385
386 return IPMI_CC_OK;
387}
388
389ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
390 ipmi_request_t request,
391 ipmi_response_t response,
392 ipmi_data_len_t dataLen,
393 ipmi_context_t context)
394{
395 SetProcessorErrConfigReq* req =
396 reinterpret_cast<SetProcessorErrConfigReq*>(request);
397
398 if (*dataLen != sizeof(SetProcessorErrConfigReq))
399 {
400 *dataLen = 0;
401 return IPMI_CC_REQ_DATA_LEN_INVALID;
402 }
403 std::string service =
404 getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
405 setDbusProperty(dbus, service, processorErrConfigObjPath,
406 processorErrConfigIntf, "ResetCfg", req->resetCfg);
407
408 setDbusProperty(dbus, service, processorErrConfigObjPath,
409 processorErrConfigIntf, "ResetErrorOccurrenceCounts",
410 req->resetErrorOccurrenceCounts);
411 *dataLen = 0;
412
413 return IPMI_CC_OK;
414}
415
Yong Li703922d2018-11-06 13:25:31 +0800416ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
417 ipmi_request_t request,
418 ipmi_response_t response,
419 ipmi_data_len_t dataLen,
420 ipmi_context_t context)
421{
422 GetOEMShutdownPolicyRes* resp =
423 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
424
425 if (*dataLen != 0)
426 {
427 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800428 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800429 *dataLen = 0;
430 return IPMI_CC_REQ_DATA_LEN_INVALID;
431 }
432
433 *dataLen = 0;
434
435 try
436 {
437 std::string service =
438 getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
439 Value variant = getDbusProperty(dbus, service, oemShutdownPolicyObjPath,
440 oemShutdownPolicyIntf,
441 oemShutdownPolicyObjPathProp);
442 resp->policy = sdbusplus::message::variant_ns::get<uint8_t>(variant);
443 // TODO needs to check if it is multi-node products,
444 // policy is only supported on node 3/4
445 resp->policySupport = shutdownPolicySupported;
446 }
447 catch (sdbusplus::exception_t& e)
448 {
449 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
450 return IPMI_CC_UNSPECIFIED_ERROR;
451 }
452
453 *dataLen = sizeof(GetOEMShutdownPolicyRes);
454 return IPMI_CC_OK;
455}
456
457ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
458 ipmi_request_t request,
459 ipmi_response_t response,
460 ipmi_data_len_t dataLen,
461 ipmi_context_t context)
462{
463 uint8_t* req = reinterpret_cast<uint8_t*>(request);
464
465 // TODO needs to check if it is multi-node products,
466 // policy is only supported on node 3/4
467 if (*dataLen != 1)
468 {
469 phosphor::logging::log<phosphor::logging::level::ERR>(
470 "oem_set_shutdown_policy: invalid input len!");
471 *dataLen = 0;
472 return IPMI_CC_REQ_DATA_LEN_INVALID;
473 }
474
475 *dataLen = 0;
476 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
477 {
478 phosphor::logging::log<phosphor::logging::level::ERR>(
479 "oem_set_shutdown_policy: invalid input!");
480 return IPMI_CC_INVALID_FIELD_REQUEST;
481 }
482
483 try
484 {
485 std::string service =
486 getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
487 setDbusProperty(dbus, service, oemShutdownPolicyObjPath,
488 oemShutdownPolicyIntf, oemShutdownPolicyObjPathProp,
489 *req);
490 }
491 catch (sdbusplus::exception_t& e)
492 {
493 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
494 return IPMI_CC_UNSPECIFIED_ERROR;
495 }
496
497 return IPMI_CC_OK;
498}
499
Kuiying Wang45f04982018-12-26 09:23:08 +0800500namespace ledAction
501{
502using namespace sdbusplus::xyz::openbmc_project::Led::server;
503std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
504 {Physical::Action::Off, 0x00},
505 {Physical::Action::On, 0x10},
506 {Physical::Action::Blink, 0x01}};
507
508std::map<uint8_t, std::string> offsetObjPath = {
509 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
510
511} // namespace ledAction
512
513int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
514 const std::string& objPath, uint8_t& state)
515{
516 try
517 {
518 std::string service = getService(bus, intf, objPath);
519 Value stateValue =
520 getDbusProperty(bus, service, objPath, intf, "State");
521 std::string strState =
522 sdbusplus::message::variant_ns::get<std::string>(stateValue);
523 state = ledAction::actionDbusToIpmi.at(
524 sdbusplus::xyz::openbmc_project::Led::server::Physical::
525 convertActionFromString(strState));
526 }
527 catch (sdbusplus::exception::SdBusError& e)
528 {
529 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
530 return -1;
531 }
532 return 0;
533}
534
535ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
536 ipmi_request_t request, ipmi_response_t response,
537 ipmi_data_len_t dataLen, ipmi_context_t context)
538{
539 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
540 // LED Status
541 //[1:0] = Reserved
542 //[3:2] = Status(Amber)
543 //[5:4] = Status(Green)
544 //[7:6] = System Identify
545 // Status definitions:
546 // 00b = Off
547 // 01b = Blink
548 // 10b = On
549 // 11b = invalid
550 if (*dataLen != 0)
551 {
552 phosphor::logging::log<phosphor::logging::level::ERR>(
553 "oem_get_led_status: invalid input len!");
554 *dataLen = 0;
555 return IPMI_CC_REQ_DATA_LEN_INVALID;
556 }
557
558 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
559 *resp = 0;
560 *dataLen = 0;
561 for (auto it = ledAction::offsetObjPath.begin();
562 it != ledAction::offsetObjPath.end(); ++it)
563 {
564 uint8_t state = 0;
565 if (-1 == getLEDState(dbus, ledIntf, it->second, state))
566 {
567 phosphor::logging::log<phosphor::logging::level::ERR>(
568 "oem_get_led_status: fail to get ID LED status!");
569 return IPMI_CC_UNSPECIFIED_ERROR;
570 }
571 *resp |= state << it->first;
572 }
573
574 *dataLen = sizeof(*resp);
575 return IPMI_CC_OK;
576}
577
Yong Li23737fe2019-02-19 08:49:55 +0800578ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
579 ipmi_request_t request,
580 ipmi_response_t response,
581 ipmi_data_len_t dataLen,
582 ipmi_context_t context)
583{
584 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
585 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
586
587 if (*dataLen == 0)
588 {
589 phosphor::logging::log<phosphor::logging::level::ERR>(
590 "CfgHostSerial: invalid input len!",
591 phosphor::logging::entry("LEN=%d", *dataLen));
592 return IPMI_CC_REQ_DATA_LEN_INVALID;
593 }
594
595 switch (req->command)
596 {
597 case getHostSerialCfgCmd:
598 {
599 if (*dataLen != 1)
600 {
601 phosphor::logging::log<phosphor::logging::level::ERR>(
602 "CfgHostSerial: invalid input len!");
603 *dataLen = 0;
604 return IPMI_CC_REQ_DATA_LEN_INVALID;
605 }
606
607 *dataLen = 0;
608
609 boost::process::ipstream is;
610 std::vector<std::string> data;
611 std::string line;
612 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
613 boost::process::std_out > is);
614
615 while (c1.running() && std::getline(is, line) && !line.empty())
616 {
617 data.push_back(line);
618 }
619
620 c1.wait();
621 if (c1.exit_code())
622 {
623 phosphor::logging::log<phosphor::logging::level::ERR>(
624 "CfgHostSerial:: error on execute",
625 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
626 // Using the default value
627 *resp = 0;
628 }
629 else
630 {
631 if (data.size() != 1)
632 {
633 phosphor::logging::log<phosphor::logging::level::ERR>(
634 "CfgHostSerial:: error on read env");
635 return IPMI_CC_UNSPECIFIED_ERROR;
636 }
637 try
638 {
639 unsigned long tmp = std::stoul(data[0]);
640 if (tmp > std::numeric_limits<uint8_t>::max())
641 {
642 throw std::out_of_range("Out of range");
643 }
644 *resp = static_cast<uint8_t>(tmp);
645 }
646 catch (const std::invalid_argument& e)
647 {
648 phosphor::logging::log<phosphor::logging::level::ERR>(
649 "invalid config ",
650 phosphor::logging::entry("ERR=%s", e.what()));
651 return IPMI_CC_UNSPECIFIED_ERROR;
652 }
653 catch (const std::out_of_range& e)
654 {
655 phosphor::logging::log<phosphor::logging::level::ERR>(
656 "out_of_range config ",
657 phosphor::logging::entry("ERR=%s", e.what()));
658 return IPMI_CC_UNSPECIFIED_ERROR;
659 }
660 }
661
662 *dataLen = 1;
663 break;
664 }
665 case setHostSerialCfgCmd:
666 {
667 if (*dataLen != sizeof(CfgHostSerialReq))
668 {
669 phosphor::logging::log<phosphor::logging::level::ERR>(
670 "CfgHostSerial: invalid input len!");
671 *dataLen = 0;
672 return IPMI_CC_REQ_DATA_LEN_INVALID;
673 }
674
675 *dataLen = 0;
676
677 if (req->parameter > HostSerialCfgParamMax)
678 {
679 phosphor::logging::log<phosphor::logging::level::ERR>(
680 "CfgHostSerial: invalid input!");
681 return IPMI_CC_INVALID_FIELD_REQUEST;
682 }
683
684 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
685 std::to_string(req->parameter));
686
687 c1.wait();
688 if (c1.exit_code())
689 {
690 phosphor::logging::log<phosphor::logging::level::ERR>(
691 "CfgHostSerial:: error on execute",
692 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
693 return IPMI_CC_UNSPECIFIED_ERROR;
694 }
695 break;
696 }
697 default:
698 phosphor::logging::log<phosphor::logging::level::ERR>(
699 "CfgHostSerial: invalid input!");
700 *dataLen = 0;
701 return IPMI_CC_INVALID_FIELD_REQUEST;
702 }
703
704 return IPMI_CC_OK;
705}
706
Jason M. Bills64796042018-10-03 16:51:55 -0700707static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800708{
709 phosphor::logging::log<phosphor::logging::level::INFO>(
710 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -0700711 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
712 ipmiOEMWildcard,
713 PRIVILEGE_USER); // wildcard default handler
714 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
715 ipmiOEMWildcard,
716 PRIVILEGE_USER); // wildcard default handler
717 ipmiPrintAndRegister(
718 netfnIntcOEMGeneral,
719 static_cast<ipmi_cmd_t>(
720 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
721 NULL, ipmiOEMGetChassisIdentifier,
722 PRIVILEGE_USER); // get chassis identifier
723 ipmiPrintAndRegister(
724 netfnIntcOEMGeneral,
725 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
726 NULL, ipmiOEMSetSystemGUID,
727 PRIVILEGE_ADMIN); // set system guid
728 ipmiPrintAndRegister(
729 netfnIntcOEMGeneral,
730 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
731 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
732 ipmiPrintAndRegister(netfnIntcOEMGeneral,
733 static_cast<ipmi_cmd_t>(
734 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
735 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
736 ipmiPrintAndRegister(
737 netfnIntcOEMGeneral,
738 static_cast<ipmi_cmd_t>(
739 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
740 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
741 ipmiPrintAndRegister(
742 netfnIntcOEMGeneral,
743 static_cast<ipmi_cmd_t>(
744 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
745 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
746 ipmiPrintAndRegister(
747 netfnIntcOEMGeneral,
748 static_cast<ipmi_cmd_t>(
749 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
750 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
751 ipmiPrintAndRegister(
752 netfnIntcOEMGeneral,
753 static_cast<ipmi_cmd_t>(
754 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
755 NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
756 ipmiPrintAndRegister(
757 netfnIntcOEMGeneral,
758 static_cast<ipmi_cmd_t>(
759 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
760 NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
Yong Li703922d2018-11-06 13:25:31 +0800761 ipmiPrintAndRegister(netfnIntcOEMGeneral,
762 static_cast<ipmi_cmd_t>(
763 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
764 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
765 ipmiPrintAndRegister(netfnIntcOEMGeneral,
766 static_cast<ipmi_cmd_t>(
767 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
768 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
Kuiying Wang45f04982018-12-26 09:23:08 +0800769 ipmiPrintAndRegister(
770 netfnIntcOEMGeneral,
771 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
772 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +0800773 ipmiPrintAndRegister(
774 netfnIntcOEMPlatform,
775 static_cast<ipmi_cmd_t>(
776 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
777 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800778 return;
779}
780
781} // namespace ipmi