blob: cc4a437bcd8f3cd1fbb2ec4ce9c0195c842cd7bf [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>
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>
28#include <oemcommands.hpp>
Jason M. Bills3f7c5e42018-10-03 14:00:41 -070029#include <phosphor-ipmi-host/utils.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080030#include <phosphor-logging/log.hpp>
31#include <sdbusplus/bus.hpp>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080032#include <string>
James Feist91244a62019-02-19 15:04:54 -080033#include <variant>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080034#include <vector>
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080035
36namespace ipmi
37{
Jason M. Bills64796042018-10-03 16:51:55 -070038static void registerOEMFunctions() __attribute__((constructor));
Jason M. Bills6d9c83f2019-02-08 14:02:19 -080039sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h
Jason M. Bills64796042018-10-03 16:51:55 -070040static constexpr size_t maxFRUStringLength = 0x3F;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080041
42// return code: 0 successful
43int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial)
44{
45 std::string objpath = "/xyz/openbmc_project/FruDevice";
46 std::string intf = "xyz.openbmc_project.FruDeviceManager";
47 std::string service = getService(bus, intf, objpath);
48 ObjectValueTree valueTree = getManagedObjects(bus, service, "/");
49 if (valueTree.empty())
50 {
51 phosphor::logging::log<phosphor::logging::level::ERR>(
52 "No object implements interface",
53 phosphor::logging::entry("INTF=%s", intf.c_str()));
54 return -1;
55 }
56
Jason M. Bills64796042018-10-03 16:51:55 -070057 for (const auto& item : valueTree)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080058 {
59 auto interface = item.second.find("xyz.openbmc_project.FruDevice");
60 if (interface == item.second.end())
61 {
62 continue;
63 }
64
65 auto property = interface->second.find("CHASSIS_SERIAL_NUMBER");
66 if (property == interface->second.end())
67 {
68 continue;
69 }
70
71 try
72 {
73 Value variant = property->second;
Jason M. Bills64796042018-10-03 16:51:55 -070074 std::string& result =
75 sdbusplus::message::variant_ns::get<std::string>(variant);
76 if (result.size() > maxFRUStringLength)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080077 {
78 phosphor::logging::log<phosphor::logging::level::ERR>(
79 "FRU serial number exceed maximum length");
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080080 return -1;
81 }
Jason M. Bills64796042018-10-03 16:51:55 -070082 serial = result;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080083 return 0;
84 }
Jason M. Bills64796042018-10-03 16:51:55 -070085 catch (sdbusplus::message::variant_ns::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080086 {
Jason M. Bills64796042018-10-03 16:51:55 -070087 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080088 return -1;
89 }
90 }
91 return -1;
92}
Jason M. Bills64796042018-10-03 16:51:55 -070093
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080094ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
95 ipmi_request_t request, ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -070096 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080097{
Jason M. Bills64796042018-10-03 16:51:55 -070098 printCommand(+netfn, +cmd);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +080099 // Status code.
100 ipmi_ret_t rc = IPMI_CC_INVALID;
Jason M. Bills64796042018-10-03 16:51:55 -0700101 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800102 return rc;
103}
104
105// Returns the Chassis Identifier (serial #)
106ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
107 ipmi_request_t request,
108 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700109 ipmi_data_len_t dataLen,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800110 ipmi_context_t context)
111{
112 std::string serial;
Jason M. Bills64796042018-10-03 16:51:55 -0700113 if (*dataLen != 0) // invalid request if there are extra parameters
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800114 {
Jason M. Bills64796042018-10-03 16:51:55 -0700115 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800116 return IPMI_CC_REQ_DATA_LEN_INVALID;
117 }
Jason M. Bills64796042018-10-03 16:51:55 -0700118 if (getChassisSerialNumber(dbus, serial) == 0)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800119 {
Jason M. Bills64796042018-10-03 16:51:55 -0700120 *dataLen = serial.size(); // length will never exceed response length
121 // as it is checked in getChassisSerialNumber
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800122 char* resp = static_cast<char*>(response);
Jason M. Bills64796042018-10-03 16:51:55 -0700123 serial.copy(resp, *dataLen);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800124 return IPMI_CC_OK;
125 }
Jason M. Bills64796042018-10-03 16:51:55 -0700126 *dataLen = 0;
127 return IPMI_CC_RESPONSE_ERROR;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800128}
129
130ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
131 ipmi_request_t request,
132 ipmi_response_t response,
Jason M. Bills64796042018-10-03 16:51:55 -0700133 ipmi_data_len_t dataLen, ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800134{
135 static constexpr size_t safeBufferLength = 50;
136 char buf[safeBufferLength] = {0};
137 GUIDData* Data = reinterpret_cast<GUIDData*>(request);
138
Jason M. Bills64796042018-10-03 16:51:55 -0700139 if (*dataLen != sizeof(GUIDData)) // 16bytes
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800140 {
Jason M. Bills64796042018-10-03 16:51:55 -0700141 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800142 return IPMI_CC_REQ_DATA_LEN_INVALID;
143 }
144
Jason M. Bills64796042018-10-03 16:51:55 -0700145 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800146
147 snprintf(
148 buf, safeBufferLength,
149 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
150 Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1,
151 Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1,
152 Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4,
153 Data->node3, Data->node2, Data->node1);
154 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
155 std::string guid = buf;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800156
157 std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID";
158 std::string intf = "xyz.openbmc_project.Common.UUID";
Jason M. Bills64796042018-10-03 16:51:55 -0700159 std::string service = getService(dbus, intf, objpath);
160 setDbusProperty(dbus, service, objpath, intf, "UUID", guid);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800161 return IPMI_CC_OK;
162}
163
164ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
165 ipmi_request_t request, ipmi_response_t response,
166 ipmi_data_len_t dataLen, ipmi_context_t context)
167{
168 DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request);
169
Jason M. Bills64796042018-10-03 16:51:55 -0700170 if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength)))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800171 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800172 *dataLen = 0;
173 return IPMI_CC_REQ_DATA_LEN_INVALID;
174 }
Jason M. Bills64796042018-10-03 16:51:55 -0700175 std::string idString((char*)data->biosId, data->biosIDLength);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800176
Jason M. Bills64796042018-10-03 16:51:55 -0700177 std::string service = getService(dbus, biosIntf, biosObjPath);
178 setDbusProperty(dbus, service, biosObjPath, biosIntf, biosProp, idString);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800179 uint8_t* bytesWritten = static_cast<uint8_t*>(response);
180 *bytesWritten =
Jason M. Bills64796042018-10-03 16:51:55 -0700181 data->biosIDLength; // how many bytes are written into storage
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800182 *dataLen = 1;
183 return IPMI_CC_OK;
184}
185
186ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
187 ipmi_request_t request,
188 ipmi_response_t response,
189 ipmi_data_len_t dataLen, ipmi_context_t context)
190{
191 GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request);
192 GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response);
193
194 if (*dataLen == 0)
195 {
Jason M. Bills64796042018-10-03 16:51:55 -0700196 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800197 return IPMI_CC_REQ_DATA_LEN_INVALID;
198 }
199
200 size_t reqDataLen = *dataLen;
201 *dataLen = 0;
Jason M. Bills64796042018-10-03 16:51:55 -0700202 if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800203 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800204 return IPMI_CC_INVALID_FIELD_REQUEST;
205 }
206
207 // handle OEM command items
Jason M. Bills64796042018-10-03 16:51:55 -0700208 switch (OEMDevEntityType(req->entityType))
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800209 {
210 case OEMDevEntityType::biosId:
211 {
212 if (sizeof(GetOemDeviceInfoReq) != reqDataLen)
213 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800214 return IPMI_CC_REQ_DATA_LEN_INVALID;
215 }
216
Jason M. Bills64796042018-10-03 16:51:55 -0700217 std::string service = getService(dbus, biosIntf, biosObjPath);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800218 try
219 {
Jason M. Bills64796042018-10-03 16:51:55 -0700220 Value variant = getDbusProperty(dbus, service, biosObjPath,
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800221 biosIntf, biosProp);
Jason M. Bills64796042018-10-03 16:51:55 -0700222 std::string& idString =
223 sdbusplus::message::variant_ns::get<std::string>(variant);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800224 if (req->offset >= idString.size())
225 {
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800226 return IPMI_CC_PARM_OUT_OF_RANGE;
227 }
Jason M. Bills64796042018-10-03 16:51:55 -0700228 size_t length = 0;
229 if (req->countToRead > (idString.size() - req->offset))
230 {
231 length = idString.size() - req->offset;
232 }
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800233 else
234 {
Jason M. Bills64796042018-10-03 16:51:55 -0700235 length = req->countToRead;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800236 }
Jason M. Bills64796042018-10-03 16:51:55 -0700237 std::copy(idString.begin() + req->offset, idString.end(),
238 res->data);
239 res->resDatalen = length;
240 *dataLen = res->resDatalen + 1;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800241 }
Jason M. Bills64796042018-10-03 16:51:55 -0700242 catch (sdbusplus::message::variant_ns::bad_variant_access& e)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800243 {
Jason M. Bills64796042018-10-03 16:51:55 -0700244 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800245 return IPMI_CC_UNSPECIFIED_ERROR;
246 }
247 }
248 break;
249
250 case OEMDevEntityType::devVer:
251 case OEMDevEntityType::sdrVer:
252 // TODO:
253 return IPMI_CC_ILLEGAL_COMMAND;
254 default:
255 return IPMI_CC_INVALID_FIELD_REQUEST;
256 }
257 return IPMI_CC_OK;
258}
259
260ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
261 ipmi_request_t request, ipmi_response_t response,
262 ipmi_data_len_t dataLen, ipmi_context_t context)
263{
264 if (*dataLen != 0)
265 {
Jason M. Bills64796042018-10-03 16:51:55 -0700266 *dataLen = 0;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800267 return IPMI_CC_REQ_DATA_LEN_INVALID;
268 }
269
270 *dataLen = 1;
271 uint8_t* res = reinterpret_cast<uint8_t*>(response);
272 // temporary fix. We don't support AIC FRU now. Just tell BIOS that no
273 // AIC is available so that BIOS will not timeout repeatly which leads to
274 // slow booting.
275 *res = 0; // Byte1=Count of SlotPosition/FruID records.
276 return IPMI_CC_OK;
277}
278
Jason M. Bills64796042018-10-03 16:51:55 -0700279ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
280 ipmi_request_t request,
281 ipmi_response_t response,
282 ipmi_data_len_t dataLen,
283 ipmi_context_t context)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800284{
Jason M. Bills64796042018-10-03 16:51:55 -0700285 GetPowerRestoreDelayRes* resp =
286 reinterpret_cast<GetPowerRestoreDelayRes*>(response);
287
288 if (*dataLen != 0)
289 {
290 *dataLen = 0;
291 return IPMI_CC_REQ_DATA_LEN_INVALID;
292 }
293
294 std::string service =
295 getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
296 Value variant =
297 getDbusProperty(dbus, service, powerRestoreDelayObjPath,
298 powerRestoreDelayIntf, powerRestoreDelayProp);
299
300 uint16_t delay = sdbusplus::message::variant_ns::get<uint16_t>(variant);
301 resp->byteLSB = delay;
302 resp->byteMSB = delay >> 8;
303
304 *dataLen = sizeof(GetPowerRestoreDelayRes);
305
306 return IPMI_CC_OK;
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800307}
308
Jason M. Bills64796042018-10-03 16:51:55 -0700309ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
310 ipmi_request_t request,
311 ipmi_response_t response,
312 ipmi_data_len_t dataLen,
313 ipmi_context_t context)
314{
315 SetPowerRestoreDelayReq* data =
316 reinterpret_cast<SetPowerRestoreDelayReq*>(request);
317 uint16_t delay = 0;
318
319 if (*dataLen != sizeof(SetPowerRestoreDelayReq))
320 {
321 *dataLen = 0;
322 return IPMI_CC_REQ_DATA_LEN_INVALID;
323 }
324 delay = data->byteMSB;
325 delay = (delay << 8) | data->byteLSB;
326 std::string service =
327 getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath);
328 setDbusProperty(dbus, service, powerRestoreDelayObjPath,
329 powerRestoreDelayIntf, powerRestoreDelayProp, delay);
330 *dataLen = 0;
331
332 return IPMI_CC_OK;
333}
334
335ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
336 ipmi_request_t request,
337 ipmi_response_t response,
338 ipmi_data_len_t dataLen,
339 ipmi_context_t context)
340{
341 GetProcessorErrConfigRes* resp =
342 reinterpret_cast<GetProcessorErrConfigRes*>(response);
343
344 if (*dataLen != 0)
345 {
346 *dataLen = 0;
347 return IPMI_CC_REQ_DATA_LEN_INVALID;
348 }
349
350 std::string service =
351 getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
352 Value variant = getDbusProperty(dbus, service, processorErrConfigObjPath,
353 processorErrConfigIntf, "ResetCfg");
354 resp->resetCfg = sdbusplus::message::variant_ns::get<uint8_t>(variant);
355
356 std::vector<uint8_t> caterrStatus;
Kuiying Wangbc546672018-11-23 15:41:05 +0800357 sdbusplus::message::variant<std::vector<uint8_t>> message;
Jason M. Bills64796042018-10-03 16:51:55 -0700358
359 auto method =
360 dbus.new_method_call(service.c_str(), processorErrConfigObjPath,
361 "org.freedesktop.DBus.Properties", "Get");
362
363 method.append(processorErrConfigIntf, "CATERRStatus");
Kuiying Wangbc546672018-11-23 15:41:05 +0800364 auto reply = dbus.call(method);
Jason M. Bills64796042018-10-03 16:51:55 -0700365
366 try
367 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800368 reply.read(message);
369 caterrStatus =
370 sdbusplus::message::variant_ns::get<std::vector<uint8_t>>(message);
Jason M. Bills64796042018-10-03 16:51:55 -0700371 }
372 catch (sdbusplus::exception_t&)
373 {
Kuiying Wangbc546672018-11-23 15:41:05 +0800374 phosphor::logging::log<phosphor::logging::level::ERR>(
Jason M. Bills64796042018-10-03 16:51:55 -0700375 "ipmiOEMGetProcessorErrConfig: error on dbus",
376 phosphor::logging::entry("PRORPERTY=CATERRStatus"),
377 phosphor::logging::entry("PATH=%s", processorErrConfigObjPath),
378 phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf));
379 return IPMI_CC_UNSPECIFIED_ERROR;
380 }
381
382 size_t len =
383 maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size();
384 caterrStatus.resize(len);
385 std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus);
386 *dataLen = sizeof(GetProcessorErrConfigRes);
387
388 return IPMI_CC_OK;
389}
390
391ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
392 ipmi_request_t request,
393 ipmi_response_t response,
394 ipmi_data_len_t dataLen,
395 ipmi_context_t context)
396{
397 SetProcessorErrConfigReq* req =
398 reinterpret_cast<SetProcessorErrConfigReq*>(request);
399
400 if (*dataLen != sizeof(SetProcessorErrConfigReq))
401 {
402 *dataLen = 0;
403 return IPMI_CC_REQ_DATA_LEN_INVALID;
404 }
405 std::string service =
406 getService(dbus, processorErrConfigIntf, processorErrConfigObjPath);
407 setDbusProperty(dbus, service, processorErrConfigObjPath,
408 processorErrConfigIntf, "ResetCfg", req->resetCfg);
409
410 setDbusProperty(dbus, service, processorErrConfigObjPath,
411 processorErrConfigIntf, "ResetErrorOccurrenceCounts",
412 req->resetErrorOccurrenceCounts);
413 *dataLen = 0;
414
415 return IPMI_CC_OK;
416}
417
Yong Li703922d2018-11-06 13:25:31 +0800418ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
419 ipmi_request_t request,
420 ipmi_response_t response,
421 ipmi_data_len_t dataLen,
422 ipmi_context_t context)
423{
424 GetOEMShutdownPolicyRes* resp =
425 reinterpret_cast<GetOEMShutdownPolicyRes*>(response);
426
427 if (*dataLen != 0)
428 {
429 phosphor::logging::log<phosphor::logging::level::ERR>(
Kuiying Wang45f04982018-12-26 09:23:08 +0800430 "oem_get_shutdown_policy: invalid input len!");
Yong Li703922d2018-11-06 13:25:31 +0800431 *dataLen = 0;
432 return IPMI_CC_REQ_DATA_LEN_INVALID;
433 }
434
435 *dataLen = 0;
436
437 try
438 {
439 std::string service =
440 getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
441 Value variant = getDbusProperty(dbus, service, oemShutdownPolicyObjPath,
442 oemShutdownPolicyIntf,
443 oemShutdownPolicyObjPathProp);
444 resp->policy = sdbusplus::message::variant_ns::get<uint8_t>(variant);
445 // TODO needs to check if it is multi-node products,
446 // policy is only supported on node 3/4
447 resp->policySupport = shutdownPolicySupported;
448 }
449 catch (sdbusplus::exception_t& e)
450 {
451 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
452 return IPMI_CC_UNSPECIFIED_ERROR;
453 }
454
455 *dataLen = sizeof(GetOEMShutdownPolicyRes);
456 return IPMI_CC_OK;
457}
458
459ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
460 ipmi_request_t request,
461 ipmi_response_t response,
462 ipmi_data_len_t dataLen,
463 ipmi_context_t context)
464{
465 uint8_t* req = reinterpret_cast<uint8_t*>(request);
466
467 // TODO needs to check if it is multi-node products,
468 // policy is only supported on node 3/4
469 if (*dataLen != 1)
470 {
471 phosphor::logging::log<phosphor::logging::level::ERR>(
472 "oem_set_shutdown_policy: invalid input len!");
473 *dataLen = 0;
474 return IPMI_CC_REQ_DATA_LEN_INVALID;
475 }
476
477 *dataLen = 0;
478 if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT))
479 {
480 phosphor::logging::log<phosphor::logging::level::ERR>(
481 "oem_set_shutdown_policy: invalid input!");
482 return IPMI_CC_INVALID_FIELD_REQUEST;
483 }
484
485 try
486 {
487 std::string service =
488 getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath);
489 setDbusProperty(dbus, service, oemShutdownPolicyObjPath,
490 oemShutdownPolicyIntf, oemShutdownPolicyObjPathProp,
491 *req);
492 }
493 catch (sdbusplus::exception_t& e)
494 {
495 phosphor::logging::log<phosphor::logging::level::ERR>(e.description());
496 return IPMI_CC_UNSPECIFIED_ERROR;
497 }
498
499 return IPMI_CC_OK;
500}
501
Kuiying Wang45f04982018-12-26 09:23:08 +0800502namespace ledAction
503{
504using namespace sdbusplus::xyz::openbmc_project::Led::server;
505std::map<Physical::Action, uint8_t> actionDbusToIpmi = {
506 {Physical::Action::Off, 0x00},
507 {Physical::Action::On, 0x10},
508 {Physical::Action::Blink, 0x01}};
509
510std::map<uint8_t, std::string> offsetObjPath = {
511 {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}};
512
513} // namespace ledAction
514
515int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf,
516 const std::string& objPath, uint8_t& state)
517{
518 try
519 {
520 std::string service = getService(bus, intf, objPath);
521 Value stateValue =
522 getDbusProperty(bus, service, objPath, intf, "State");
523 std::string strState =
524 sdbusplus::message::variant_ns::get<std::string>(stateValue);
525 state = ledAction::actionDbusToIpmi.at(
526 sdbusplus::xyz::openbmc_project::Led::server::Physical::
527 convertActionFromString(strState));
528 }
529 catch (sdbusplus::exception::SdBusError& e)
530 {
531 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
532 return -1;
533 }
534 return 0;
535}
536
537ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
538 ipmi_request_t request, ipmi_response_t response,
539 ipmi_data_len_t dataLen, ipmi_context_t context)
540{
541 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
542 // LED Status
543 //[1:0] = Reserved
544 //[3:2] = Status(Amber)
545 //[5:4] = Status(Green)
546 //[7:6] = System Identify
547 // Status definitions:
548 // 00b = Off
549 // 01b = Blink
550 // 10b = On
551 // 11b = invalid
552 if (*dataLen != 0)
553 {
554 phosphor::logging::log<phosphor::logging::level::ERR>(
555 "oem_get_led_status: invalid input len!");
556 *dataLen = 0;
557 return IPMI_CC_REQ_DATA_LEN_INVALID;
558 }
559
560 phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status");
561 *resp = 0;
562 *dataLen = 0;
563 for (auto it = ledAction::offsetObjPath.begin();
564 it != ledAction::offsetObjPath.end(); ++it)
565 {
566 uint8_t state = 0;
567 if (-1 == getLEDState(dbus, ledIntf, it->second, state))
568 {
569 phosphor::logging::log<phosphor::logging::level::ERR>(
570 "oem_get_led_status: fail to get ID LED status!");
571 return IPMI_CC_UNSPECIFIED_ERROR;
572 }
573 *resp |= state << it->first;
574 }
575
576 *dataLen = sizeof(*resp);
577 return IPMI_CC_OK;
578}
579
Yong Li23737fe2019-02-19 08:49:55 +0800580ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
581 ipmi_request_t request,
582 ipmi_response_t response,
583 ipmi_data_len_t dataLen,
584 ipmi_context_t context)
585{
586 CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request);
587 uint8_t* resp = reinterpret_cast<uint8_t*>(response);
588
589 if (*dataLen == 0)
590 {
591 phosphor::logging::log<phosphor::logging::level::ERR>(
592 "CfgHostSerial: invalid input len!",
593 phosphor::logging::entry("LEN=%d", *dataLen));
594 return IPMI_CC_REQ_DATA_LEN_INVALID;
595 }
596
597 switch (req->command)
598 {
599 case getHostSerialCfgCmd:
600 {
601 if (*dataLen != 1)
602 {
603 phosphor::logging::log<phosphor::logging::level::ERR>(
604 "CfgHostSerial: invalid input len!");
605 *dataLen = 0;
606 return IPMI_CC_REQ_DATA_LEN_INVALID;
607 }
608
609 *dataLen = 0;
610
611 boost::process::ipstream is;
612 std::vector<std::string> data;
613 std::string line;
614 boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName,
615 boost::process::std_out > is);
616
617 while (c1.running() && std::getline(is, line) && !line.empty())
618 {
619 data.push_back(line);
620 }
621
622 c1.wait();
623 if (c1.exit_code())
624 {
625 phosphor::logging::log<phosphor::logging::level::ERR>(
626 "CfgHostSerial:: error on execute",
627 phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd));
628 // Using the default value
629 *resp = 0;
630 }
631 else
632 {
633 if (data.size() != 1)
634 {
635 phosphor::logging::log<phosphor::logging::level::ERR>(
636 "CfgHostSerial:: error on read env");
637 return IPMI_CC_UNSPECIFIED_ERROR;
638 }
639 try
640 {
641 unsigned long tmp = std::stoul(data[0]);
642 if (tmp > std::numeric_limits<uint8_t>::max())
643 {
644 throw std::out_of_range("Out of range");
645 }
646 *resp = static_cast<uint8_t>(tmp);
647 }
648 catch (const std::invalid_argument& e)
649 {
650 phosphor::logging::log<phosphor::logging::level::ERR>(
651 "invalid config ",
652 phosphor::logging::entry("ERR=%s", e.what()));
653 return IPMI_CC_UNSPECIFIED_ERROR;
654 }
655 catch (const std::out_of_range& e)
656 {
657 phosphor::logging::log<phosphor::logging::level::ERR>(
658 "out_of_range config ",
659 phosphor::logging::entry("ERR=%s", e.what()));
660 return IPMI_CC_UNSPECIFIED_ERROR;
661 }
662 }
663
664 *dataLen = 1;
665 break;
666 }
667 case setHostSerialCfgCmd:
668 {
669 if (*dataLen != sizeof(CfgHostSerialReq))
670 {
671 phosphor::logging::log<phosphor::logging::level::ERR>(
672 "CfgHostSerial: invalid input len!");
673 *dataLen = 0;
674 return IPMI_CC_REQ_DATA_LEN_INVALID;
675 }
676
677 *dataLen = 0;
678
679 if (req->parameter > HostSerialCfgParamMax)
680 {
681 phosphor::logging::log<phosphor::logging::level::ERR>(
682 "CfgHostSerial: invalid input!");
683 return IPMI_CC_INVALID_FIELD_REQUEST;
684 }
685
686 boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName,
687 std::to_string(req->parameter));
688
689 c1.wait();
690 if (c1.exit_code())
691 {
692 phosphor::logging::log<phosphor::logging::level::ERR>(
693 "CfgHostSerial:: error on execute",
694 phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd));
695 return IPMI_CC_UNSPECIFIED_ERROR;
696 }
697 break;
698 }
699 default:
700 phosphor::logging::log<phosphor::logging::level::ERR>(
701 "CfgHostSerial: invalid input!");
702 *dataLen = 0;
703 return IPMI_CC_INVALID_FIELD_REQUEST;
704 }
705
706 return IPMI_CC_OK;
707}
708
James Feist91244a62019-02-19 15:04:54 -0800709constexpr const char* thermalModeInterface =
710 "xyz.openbmc_project.Control.ThermalMode";
711constexpr const char* thermalModePath =
712 "/xyz/openbmc_project/control/thermal_mode";
713
714bool getFanProfileInterface(
715 sdbusplus::bus::bus& bus,
716 boost::container::flat_map<
717 std::string, std::variant<std::vector<std::string>, std::string>>& resp)
718{
719 auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF,
720 "GetAll");
721 call.append(thermalModeInterface);
722 try
723 {
724 auto data = bus.call(call);
725 data.read(resp);
726 }
727 catch (sdbusplus::exception_t& e)
728 {
729 phosphor::logging::log<phosphor::logging::level::ERR>(
730 "getFanProfileInterface: can't get thermal mode!",
731 phosphor::logging::entry("ERR=%s", e.what()));
732 return false;
733 }
734 return true;
735}
736
737ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
738 ipmi_request_t request, ipmi_response_t response,
739 ipmi_data_len_t dataLen, ipmi_context_t context)
740{
741
742 if (*dataLen < 2 || *dataLen > 7)
743 {
744 phosphor::logging::log<phosphor::logging::level::ERR>(
745 "ipmiOEMSetFanConfig: invalid input len!");
746 *dataLen = 0;
747 return IPMI_CC_REQ_DATA_LEN_INVALID;
748 }
749
750 // todo: tell bios to only send first 2 bytes
751
752 SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request);
753 boost::container::flat_map<
754 std::string, std::variant<std::vector<std::string>, std::string>>
755 profileData;
756 if (!getFanProfileInterface(dbus, profileData))
757 {
758 return IPMI_CC_UNSPECIFIED_ERROR;
759 }
760
761 std::vector<std::string>* supported =
762 std::get_if<std::vector<std::string>>(&profileData["Supported"]);
763 if (supported == nullptr)
764 {
765 return IPMI_CC_INVALID_FIELD_REQUEST;
766 }
767 std::string mode;
768 if (req->flags &
769 (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode)))
770 {
771 bool performanceMode =
772 (req->flags & (1 << static_cast<uint8_t>(
773 setFanProfileFlags::performAcousSelect))) > 0;
774
775 if (performanceMode)
776 {
777
778 if (std::find(supported->begin(), supported->end(),
779 "Performance") != supported->end())
780 {
781 mode = "Performance";
782 }
783 }
784 else
785 {
786
787 if (std::find(supported->begin(), supported->end(), "Acoustic") !=
788 supported->end())
789 {
790 mode = "Acoustic";
791 }
792 }
793 if (mode.empty())
794 {
795 return IPMI_CC_INVALID_FIELD_REQUEST;
796 }
797 setDbusProperty(dbus, settingsBusName, thermalModePath,
798 thermalModeInterface, "Current", mode);
799 }
800
801 return IPMI_CC_OK;
802}
803
804ipmi_ret_t ipmiOEMGetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
805 ipmi_request_t request, ipmi_response_t response,
806 ipmi_data_len_t dataLen, ipmi_context_t context)
807{
808
809 if (*dataLen > 1)
810 {
811 phosphor::logging::log<phosphor::logging::level::ERR>(
812 "ipmiOEMGetFanConfig: invalid input len!");
813 *dataLen = 0;
814 return IPMI_CC_REQ_DATA_LEN_INVALID;
815 }
816
817 // todo: talk to bios about needing less information
818
819 GetFanConfigResp* resp = reinterpret_cast<GetFanConfigResp*>(response);
820 *dataLen = sizeof(GetFanConfigResp);
821
822 boost::container::flat_map<
823 std::string, std::variant<std::vector<std::string>, std::string>>
824 profileData;
825
826 if (!getFanProfileInterface(dbus, profileData))
827 {
828 return IPMI_CC_UNSPECIFIED_ERROR;
829 }
830
831 std::string* current = std::get_if<std::string>(&profileData["Current"]);
832
833 if (current == nullptr)
834 {
835 phosphor::logging::log<phosphor::logging::level::ERR>(
836 "ipmiOEMGetFanConfig: can't get current mode!");
837 return IPMI_CC_UNSPECIFIED_ERROR;
838 }
839 bool performance = (*current == "Performance");
840
841 if (performance)
842 {
843 resp->flags |= 1 << 2;
844 }
845
846 return IPMI_CC_OK;
847}
848
Jason M. Bills64796042018-10-03 16:51:55 -0700849static void registerOEMFunctions(void)
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800850{
851 phosphor::logging::log<phosphor::logging::level::INFO>(
852 "Registering OEM commands");
Jason M. Bills64796042018-10-03 16:51:55 -0700853 ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL,
854 ipmiOEMWildcard,
855 PRIVILEGE_USER); // wildcard default handler
856 ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL,
857 ipmiOEMWildcard,
858 PRIVILEGE_USER); // wildcard default handler
859 ipmiPrintAndRegister(
860 netfnIntcOEMGeneral,
861 static_cast<ipmi_cmd_t>(
862 IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier),
863 NULL, ipmiOEMGetChassisIdentifier,
864 PRIVILEGE_USER); // get chassis identifier
865 ipmiPrintAndRegister(
866 netfnIntcOEMGeneral,
867 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID),
868 NULL, ipmiOEMSetSystemGUID,
869 PRIVILEGE_ADMIN); // set system guid
870 ipmiPrintAndRegister(
871 netfnIntcOEMGeneral,
872 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID),
873 NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN);
874 ipmiPrintAndRegister(netfnIntcOEMGeneral,
875 static_cast<ipmi_cmd_t>(
876 IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo),
877 NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER);
878 ipmiPrintAndRegister(
879 netfnIntcOEMGeneral,
880 static_cast<ipmi_cmd_t>(
881 IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords),
882 NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER);
883 ipmiPrintAndRegister(
884 netfnIntcOEMGeneral,
885 static_cast<ipmi_cmd_t>(
886 IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay),
887 NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR);
888 ipmiPrintAndRegister(
889 netfnIntcOEMGeneral,
890 static_cast<ipmi_cmd_t>(
891 IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay),
892 NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER);
893 ipmiPrintAndRegister(
894 netfnIntcOEMGeneral,
895 static_cast<ipmi_cmd_t>(
896 IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig),
897 NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER);
898 ipmiPrintAndRegister(
899 netfnIntcOEMGeneral,
900 static_cast<ipmi_cmd_t>(
901 IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig),
902 NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN);
Yong Li703922d2018-11-06 13:25:31 +0800903 ipmiPrintAndRegister(netfnIntcOEMGeneral,
904 static_cast<ipmi_cmd_t>(
905 IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy),
906 NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN);
907 ipmiPrintAndRegister(netfnIntcOEMGeneral,
908 static_cast<ipmi_cmd_t>(
909 IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy),
910 NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN);
James Feist91244a62019-02-19 15:04:54 -0800911
912 ipmiPrintAndRegister(
913 netfnIntcOEMGeneral,
914 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig),
915 NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER);
916
917 ipmiPrintAndRegister(
918 netfnIntcOEMGeneral,
919 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig),
920 NULL, ipmiOEMGetFanConfig, PRIVILEGE_USER);
921
Kuiying Wang45f04982018-12-26 09:23:08 +0800922 ipmiPrintAndRegister(
923 netfnIntcOEMGeneral,
924 static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus),
925 NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN);
Yong Li23737fe2019-02-19 08:49:55 +0800926 ipmiPrintAndRegister(
927 netfnIntcOEMPlatform,
928 static_cast<ipmi_cmd_t>(
929 IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed),
930 NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN);
Jia, Chunhuia835eaa2018-09-05 09:00:41 +0800931 return;
932}
933
934} // namespace ipmi