1a835eaa0SJia, Chunhui /* 2a835eaa0SJia, Chunhui // Copyright (c) 2018 Intel Corporation 3a835eaa0SJia, Chunhui // 4a835eaa0SJia, Chunhui // Licensed under the Apache License, Version 2.0 (the "License"); 5a835eaa0SJia, Chunhui // you may not use this file except in compliance with the License. 6a835eaa0SJia, Chunhui // You may obtain a copy of the License at 7a835eaa0SJia, Chunhui // 8a835eaa0SJia, Chunhui // http://www.apache.org/licenses/LICENSE-2.0 9a835eaa0SJia, Chunhui // 10a835eaa0SJia, Chunhui // Unless required by applicable law or agreed to in writing, software 11a835eaa0SJia, Chunhui // distributed under the License is distributed on an "AS IS" BASIS, 12a835eaa0SJia, Chunhui // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a835eaa0SJia, Chunhui // See the License for the specific language governing permissions and 14a835eaa0SJia, Chunhui // limitations under the License. 15a835eaa0SJia, Chunhui */ 16a835eaa0SJia, Chunhui 1764796041SJason M. Bills #include "xyz/openbmc_project/Common/error.hpp" 1845f04988SKuiying Wang #include "xyz/openbmc_project/Led/Physical/server.hpp" 1964796041SJason M. Bills 20cc49b54bSJia, Chunhui #include <systemd/sd-journal.h> 21a835eaa0SJia, Chunhui 22a835eaa0SJia, Chunhui #include <array> 2391244a6aSJames Feist #include <boost/container/flat_map.hpp> 2423737fe3SYong Li #include <boost/process/child.hpp> 2523737fe3SYong Li #include <boost/process/io.hpp> 2664796041SJason M. Bills #include <commandutils.hpp> 27a835eaa0SJia, Chunhui #include <iostream> 28cc49b54bSJia, Chunhui #include <ipmid/api.hpp> 295480ef62SVernon Mauery #include <ipmid/utils.hpp> 30a835eaa0SJia, Chunhui #include <oemcommands.hpp> 31a835eaa0SJia, Chunhui #include <phosphor-logging/log.hpp> 32a835eaa0SJia, Chunhui #include <sdbusplus/bus.hpp> 33d509eb91SSuryakanth Sekar #include <sdbusplus/message/types.hpp> 34a835eaa0SJia, Chunhui #include <string> 3591244a6aSJames Feist #include <variant> 36a835eaa0SJia, Chunhui #include <vector> 37a835eaa0SJia, Chunhui 38a835eaa0SJia, Chunhui namespace ipmi 39a835eaa0SJia, Chunhui { 4064796041SJason M. Bills static void registerOEMFunctions() __attribute__((constructor)); 416d9c83fdSJason M. Bills sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); // from ipmid/api.h 4264796041SJason M. Bills static constexpr size_t maxFRUStringLength = 0x3F; 43a835eaa0SJia, Chunhui 44d509eb91SSuryakanth Sekar static constexpr auto ethernetIntf = 45d509eb91SSuryakanth Sekar "xyz.openbmc_project.Network.EthernetInterface"; 46d509eb91SSuryakanth Sekar static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP"; 47d509eb91SSuryakanth Sekar static constexpr auto networkService = "xyz.openbmc_project.Network"; 48d509eb91SSuryakanth Sekar static constexpr auto networkRoot = "/xyz/openbmc_project/network"; 49d509eb91SSuryakanth Sekar 50a835eaa0SJia, Chunhui // return code: 0 successful 51a835eaa0SJia, Chunhui int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial) 52a835eaa0SJia, Chunhui { 53a835eaa0SJia, Chunhui std::string objpath = "/xyz/openbmc_project/FruDevice"; 54a835eaa0SJia, Chunhui std::string intf = "xyz.openbmc_project.FruDeviceManager"; 55a835eaa0SJia, Chunhui std::string service = getService(bus, intf, objpath); 56a835eaa0SJia, Chunhui ObjectValueTree valueTree = getManagedObjects(bus, service, "/"); 57a835eaa0SJia, Chunhui if (valueTree.empty()) 58a835eaa0SJia, Chunhui { 59a835eaa0SJia, Chunhui phosphor::logging::log<phosphor::logging::level::ERR>( 60a835eaa0SJia, Chunhui "No object implements interface", 61a835eaa0SJia, Chunhui phosphor::logging::entry("INTF=%s", intf.c_str())); 62a835eaa0SJia, Chunhui return -1; 63a835eaa0SJia, Chunhui } 64a835eaa0SJia, Chunhui 6564796041SJason M. Bills for (const auto& item : valueTree) 66a835eaa0SJia, Chunhui { 67a835eaa0SJia, Chunhui auto interface = item.second.find("xyz.openbmc_project.FruDevice"); 68a835eaa0SJia, Chunhui if (interface == item.second.end()) 69a835eaa0SJia, Chunhui { 70a835eaa0SJia, Chunhui continue; 71a835eaa0SJia, Chunhui } 72a835eaa0SJia, Chunhui 73a835eaa0SJia, Chunhui auto property = interface->second.find("CHASSIS_SERIAL_NUMBER"); 74a835eaa0SJia, Chunhui if (property == interface->second.end()) 75a835eaa0SJia, Chunhui { 76a835eaa0SJia, Chunhui continue; 77a835eaa0SJia, Chunhui } 78a835eaa0SJia, Chunhui 79a835eaa0SJia, Chunhui try 80a835eaa0SJia, Chunhui { 81a835eaa0SJia, Chunhui Value variant = property->second; 8264796041SJason M. Bills std::string& result = 8364796041SJason M. Bills sdbusplus::message::variant_ns::get<std::string>(variant); 8464796041SJason M. Bills if (result.size() > maxFRUStringLength) 85a835eaa0SJia, Chunhui { 86a835eaa0SJia, Chunhui phosphor::logging::log<phosphor::logging::level::ERR>( 87a835eaa0SJia, Chunhui "FRU serial number exceed maximum length"); 88a835eaa0SJia, Chunhui return -1; 89a835eaa0SJia, Chunhui } 90a835eaa0SJia, Chunhui serial = result; 91a835eaa0SJia, Chunhui return 0; 92a835eaa0SJia, Chunhui } 9364796041SJason M. Bills catch (sdbusplus::message::variant_ns::bad_variant_access& e) 94a835eaa0SJia, Chunhui { 9564796041SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 96a835eaa0SJia, Chunhui return -1; 97a835eaa0SJia, Chunhui } 98a835eaa0SJia, Chunhui } 99a835eaa0SJia, Chunhui return -1; 100a835eaa0SJia, Chunhui } 10164796041SJason M. Bills 102a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMWildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 103a835eaa0SJia, Chunhui ipmi_request_t request, ipmi_response_t response, 10464796041SJason M. Bills ipmi_data_len_t dataLen, ipmi_context_t context) 105a835eaa0SJia, Chunhui { 10664796041SJason M. Bills printCommand(+netfn, +cmd); 107a835eaa0SJia, Chunhui // Status code. 108a835eaa0SJia, Chunhui ipmi_ret_t rc = IPMI_CC_INVALID; 10964796041SJason M. Bills *dataLen = 0; 110a835eaa0SJia, Chunhui return rc; 111a835eaa0SJia, Chunhui } 112a835eaa0SJia, Chunhui 113a835eaa0SJia, Chunhui // Returns the Chassis Identifier (serial #) 114a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 115a835eaa0SJia, Chunhui ipmi_request_t request, 116a835eaa0SJia, Chunhui ipmi_response_t response, 11764796041SJason M. Bills ipmi_data_len_t dataLen, 118a835eaa0SJia, Chunhui ipmi_context_t context) 119a835eaa0SJia, Chunhui { 120a835eaa0SJia, Chunhui std::string serial; 12164796041SJason M. Bills if (*dataLen != 0) // invalid request if there are extra parameters 122a835eaa0SJia, Chunhui { 12364796041SJason M. Bills *dataLen = 0; 124a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 125a835eaa0SJia, Chunhui } 12664796041SJason M. Bills if (getChassisSerialNumber(dbus, serial) == 0) 127a835eaa0SJia, Chunhui { 12864796041SJason M. Bills *dataLen = serial.size(); // length will never exceed response length 129a835eaa0SJia, Chunhui // as it is checked in getChassisSerialNumber 130a835eaa0SJia, Chunhui char* resp = static_cast<char*>(response); 13164796041SJason M. Bills serial.copy(resp, *dataLen); 132a835eaa0SJia, Chunhui return IPMI_CC_OK; 133a835eaa0SJia, Chunhui } 13464796041SJason M. Bills *dataLen = 0; 135a835eaa0SJia, Chunhui return IPMI_CC_RESPONSE_ERROR; 136a835eaa0SJia, Chunhui } 137a835eaa0SJia, Chunhui 138a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 139a835eaa0SJia, Chunhui ipmi_request_t request, 140a835eaa0SJia, Chunhui ipmi_response_t response, 14164796041SJason M. Bills ipmi_data_len_t dataLen, ipmi_context_t context) 142a835eaa0SJia, Chunhui { 143a835eaa0SJia, Chunhui static constexpr size_t safeBufferLength = 50; 144a835eaa0SJia, Chunhui char buf[safeBufferLength] = {0}; 145a835eaa0SJia, Chunhui GUIDData* Data = reinterpret_cast<GUIDData*>(request); 146a835eaa0SJia, Chunhui 14764796041SJason M. Bills if (*dataLen != sizeof(GUIDData)) // 16bytes 148a835eaa0SJia, Chunhui { 14964796041SJason M. Bills *dataLen = 0; 150a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 151a835eaa0SJia, Chunhui } 152a835eaa0SJia, Chunhui 15364796041SJason M. Bills *dataLen = 0; 154a835eaa0SJia, Chunhui 155a835eaa0SJia, Chunhui snprintf( 156a835eaa0SJia, Chunhui buf, safeBufferLength, 157a835eaa0SJia, Chunhui "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 158a835eaa0SJia, Chunhui Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1, 159a835eaa0SJia, Chunhui Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1, 160a835eaa0SJia, Chunhui Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4, 161a835eaa0SJia, Chunhui Data->node3, Data->node2, Data->node1); 162a835eaa0SJia, Chunhui // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 163a835eaa0SJia, Chunhui std::string guid = buf; 164a835eaa0SJia, Chunhui 165a835eaa0SJia, Chunhui std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID"; 166a835eaa0SJia, Chunhui std::string intf = "xyz.openbmc_project.Common.UUID"; 16764796041SJason M. Bills std::string service = getService(dbus, intf, objpath); 16864796041SJason M. Bills setDbusProperty(dbus, service, objpath, intf, "UUID", guid); 169a835eaa0SJia, Chunhui return IPMI_CC_OK; 170a835eaa0SJia, Chunhui } 171a835eaa0SJia, Chunhui 172a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 173a835eaa0SJia, Chunhui ipmi_request_t request, ipmi_response_t response, 174a835eaa0SJia, Chunhui ipmi_data_len_t dataLen, ipmi_context_t context) 175a835eaa0SJia, Chunhui { 176a835eaa0SJia, Chunhui DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request); 177a835eaa0SJia, Chunhui 17864796041SJason M. Bills if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength))) 179a835eaa0SJia, Chunhui { 180a835eaa0SJia, Chunhui *dataLen = 0; 181a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 182a835eaa0SJia, Chunhui } 18364796041SJason M. Bills std::string idString((char*)data->biosId, data->biosIDLength); 184a835eaa0SJia, Chunhui 18564796041SJason M. Bills std::string service = getService(dbus, biosIntf, biosObjPath); 18664796041SJason M. Bills setDbusProperty(dbus, service, biosObjPath, biosIntf, biosProp, idString); 187a835eaa0SJia, Chunhui uint8_t* bytesWritten = static_cast<uint8_t*>(response); 188a835eaa0SJia, Chunhui *bytesWritten = 18964796041SJason M. Bills data->biosIDLength; // how many bytes are written into storage 190a835eaa0SJia, Chunhui *dataLen = 1; 191a835eaa0SJia, Chunhui return IPMI_CC_OK; 192a835eaa0SJia, Chunhui } 193a835eaa0SJia, Chunhui 194a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetDeviceInfo(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 195a835eaa0SJia, Chunhui ipmi_request_t request, 196a835eaa0SJia, Chunhui ipmi_response_t response, 197a835eaa0SJia, Chunhui ipmi_data_len_t dataLen, ipmi_context_t context) 198a835eaa0SJia, Chunhui { 199a835eaa0SJia, Chunhui GetOemDeviceInfoReq* req = reinterpret_cast<GetOemDeviceInfoReq*>(request); 200a835eaa0SJia, Chunhui GetOemDeviceInfoRes* res = reinterpret_cast<GetOemDeviceInfoRes*>(response); 201a835eaa0SJia, Chunhui 202a835eaa0SJia, Chunhui if (*dataLen == 0) 203a835eaa0SJia, Chunhui { 20464796041SJason M. Bills *dataLen = 0; 205a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 206a835eaa0SJia, Chunhui } 207a835eaa0SJia, Chunhui 208a835eaa0SJia, Chunhui size_t reqDataLen = *dataLen; 209a835eaa0SJia, Chunhui *dataLen = 0; 21064796041SJason M. Bills if (req->entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer)) 211a835eaa0SJia, Chunhui { 212a835eaa0SJia, Chunhui return IPMI_CC_INVALID_FIELD_REQUEST; 213a835eaa0SJia, Chunhui } 214a835eaa0SJia, Chunhui 215a835eaa0SJia, Chunhui // handle OEM command items 21664796041SJason M. Bills switch (OEMDevEntityType(req->entityType)) 217a835eaa0SJia, Chunhui { 218a835eaa0SJia, Chunhui case OEMDevEntityType::biosId: 219a835eaa0SJia, Chunhui { 220a835eaa0SJia, Chunhui if (sizeof(GetOemDeviceInfoReq) != reqDataLen) 221a835eaa0SJia, Chunhui { 222a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 223a835eaa0SJia, Chunhui } 224a835eaa0SJia, Chunhui 22564796041SJason M. Bills std::string service = getService(dbus, biosIntf, biosObjPath); 226a835eaa0SJia, Chunhui try 227a835eaa0SJia, Chunhui { 22864796041SJason M. Bills Value variant = getDbusProperty(dbus, service, biosObjPath, 229a835eaa0SJia, Chunhui biosIntf, biosProp); 23064796041SJason M. Bills std::string& idString = 23164796041SJason M. Bills sdbusplus::message::variant_ns::get<std::string>(variant); 232a835eaa0SJia, Chunhui if (req->offset >= idString.size()) 233a835eaa0SJia, Chunhui { 234a835eaa0SJia, Chunhui return IPMI_CC_PARM_OUT_OF_RANGE; 235a835eaa0SJia, Chunhui } 236a835eaa0SJia, Chunhui size_t length = 0; 237a835eaa0SJia, Chunhui if (req->countToRead > (idString.size() - req->offset)) 238a835eaa0SJia, Chunhui { 239a835eaa0SJia, Chunhui length = idString.size() - req->offset; 240a835eaa0SJia, Chunhui } 241a835eaa0SJia, Chunhui else 242a835eaa0SJia, Chunhui { 243a835eaa0SJia, Chunhui length = req->countToRead; 244a835eaa0SJia, Chunhui } 245a835eaa0SJia, Chunhui std::copy(idString.begin() + req->offset, idString.end(), 246a835eaa0SJia, Chunhui res->data); 247a835eaa0SJia, Chunhui res->resDatalen = length; 248a835eaa0SJia, Chunhui *dataLen = res->resDatalen + 1; 249a835eaa0SJia, Chunhui } 25064796041SJason M. Bills catch (sdbusplus::message::variant_ns::bad_variant_access& e) 251a835eaa0SJia, Chunhui { 25264796041SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 253a835eaa0SJia, Chunhui return IPMI_CC_UNSPECIFIED_ERROR; 254a835eaa0SJia, Chunhui } 255a835eaa0SJia, Chunhui } 256a835eaa0SJia, Chunhui break; 257a835eaa0SJia, Chunhui 258a835eaa0SJia, Chunhui case OEMDevEntityType::devVer: 259a835eaa0SJia, Chunhui case OEMDevEntityType::sdrVer: 260a835eaa0SJia, Chunhui // TODO: 261a835eaa0SJia, Chunhui return IPMI_CC_ILLEGAL_COMMAND; 262a835eaa0SJia, Chunhui default: 263a835eaa0SJia, Chunhui return IPMI_CC_INVALID_FIELD_REQUEST; 264a835eaa0SJia, Chunhui } 265a835eaa0SJia, Chunhui return IPMI_CC_OK; 266a835eaa0SJia, Chunhui } 267a835eaa0SJia, Chunhui 268a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 269a835eaa0SJia, Chunhui ipmi_request_t request, ipmi_response_t response, 270a835eaa0SJia, Chunhui ipmi_data_len_t dataLen, ipmi_context_t context) 271a835eaa0SJia, Chunhui { 272a835eaa0SJia, Chunhui if (*dataLen != 0) 273a835eaa0SJia, Chunhui { 27464796041SJason M. Bills *dataLen = 0; 275a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 276a835eaa0SJia, Chunhui } 277a835eaa0SJia, Chunhui 278a835eaa0SJia, Chunhui *dataLen = 1; 279a835eaa0SJia, Chunhui uint8_t* res = reinterpret_cast<uint8_t*>(response); 280a835eaa0SJia, Chunhui // temporary fix. We don't support AIC FRU now. Just tell BIOS that no 281a835eaa0SJia, Chunhui // AIC is available so that BIOS will not timeout repeatly which leads to 282a835eaa0SJia, Chunhui // slow booting. 283a835eaa0SJia, Chunhui *res = 0; // Byte1=Count of SlotPosition/FruID records. 284a835eaa0SJia, Chunhui return IPMI_CC_OK; 285a835eaa0SJia, Chunhui } 286a835eaa0SJia, Chunhui 28764796041SJason M. Bills ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 28864796041SJason M. Bills ipmi_request_t request, 28964796041SJason M. Bills ipmi_response_t response, 29064796041SJason M. Bills ipmi_data_len_t dataLen, 29164796041SJason M. Bills ipmi_context_t context) 292a835eaa0SJia, Chunhui { 29364796041SJason M. Bills GetPowerRestoreDelayRes* resp = 29464796041SJason M. Bills reinterpret_cast<GetPowerRestoreDelayRes*>(response); 29564796041SJason M. Bills 29664796041SJason M. Bills if (*dataLen != 0) 29764796041SJason M. Bills { 29864796041SJason M. Bills *dataLen = 0; 29964796041SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 300a835eaa0SJia, Chunhui } 301a835eaa0SJia, Chunhui 30264796041SJason M. Bills std::string service = 30364796041SJason M. Bills getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 30464796041SJason M. Bills Value variant = 30564796041SJason M. Bills getDbusProperty(dbus, service, powerRestoreDelayObjPath, 30664796041SJason M. Bills powerRestoreDelayIntf, powerRestoreDelayProp); 30764796041SJason M. Bills 30864796041SJason M. Bills uint16_t delay = sdbusplus::message::variant_ns::get<uint16_t>(variant); 30964796041SJason M. Bills resp->byteLSB = delay; 31064796041SJason M. Bills resp->byteMSB = delay >> 8; 31164796041SJason M. Bills 31264796041SJason M. Bills *dataLen = sizeof(GetPowerRestoreDelayRes); 31364796041SJason M. Bills 31464796041SJason M. Bills return IPMI_CC_OK; 31564796041SJason M. Bills } 31664796041SJason M. Bills 317cc49b54bSJia, Chunhui static uint8_t bcdToDec(uint8_t val) 318cc49b54bSJia, Chunhui { 319cc49b54bSJia, Chunhui return ((val / 16 * 10) + (val % 16)); 320cc49b54bSJia, Chunhui } 321cc49b54bSJia, Chunhui 322cc49b54bSJia, Chunhui // Allows an update utility or system BIOS to send the status of an embedded 323cc49b54bSJia, Chunhui // firmware update attempt to the BMC. After received, BMC will create a logging 324cc49b54bSJia, Chunhui // record. 325cc49b54bSJia, Chunhui ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target, 326cc49b54bSJia, Chunhui uint8_t majorRevision, 327cc49b54bSJia, Chunhui uint8_t minorRevision, 328cc49b54bSJia, Chunhui uint32_t auxInfo) 329cc49b54bSJia, Chunhui { 330cc49b54bSJia, Chunhui std::string firmware; 331cc49b54bSJia, Chunhui target = (target & selEvtTargetMask) >> selEvtTargetShift; 332cc49b54bSJia, Chunhui 333cc49b54bSJia, Chunhui /* make sure the status is 0, 1, or 2 as per the spec */ 334cc49b54bSJia, Chunhui if (status > 2) 335cc49b54bSJia, Chunhui { 336cc49b54bSJia, Chunhui return ipmi::response(ipmi::ccInvalidFieldRequest); 337cc49b54bSJia, Chunhui } 338cc49b54bSJia, Chunhui /*orignal OEM command is to record OEM SEL. 339cc49b54bSJia, Chunhui But openbmc does not support OEM SEL, so we redirect it to redfish event 340cc49b54bSJia, Chunhui logging. */ 341cc49b54bSJia, Chunhui std::string buildInfo; 342cc49b54bSJia, Chunhui std::string action; 343cc49b54bSJia, Chunhui switch (FWUpdateTarget(target)) 344cc49b54bSJia, Chunhui { 345cc49b54bSJia, Chunhui case FWUpdateTarget::targetBMC: 346cc49b54bSJia, Chunhui firmware = "BMC"; 347cc49b54bSJia, Chunhui buildInfo = " major: " + std::to_string(majorRevision) + 348cc49b54bSJia, Chunhui " minor: " + 349cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 350cc49b54bSJia, Chunhui " BuildID: " + std::to_string(auxInfo); 351cc49b54bSJia, Chunhui buildInfo += std::to_string(auxInfo); 352cc49b54bSJia, Chunhui break; 353cc49b54bSJia, Chunhui case FWUpdateTarget::targetBIOS: 354cc49b54bSJia, Chunhui firmware = "BIOS"; 355cc49b54bSJia, Chunhui buildInfo = 356cc49b54bSJia, Chunhui " major: " + 357cc49b54bSJia, Chunhui std::to_string(bcdToDec(majorRevision)) + // BCD encoded 358cc49b54bSJia, Chunhui " minor: " + 359cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 360cc49b54bSJia, Chunhui " ReleaseNumber: " + // ASCII encoded 361cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') + 362cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') + 363cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') + 364cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0'); 365cc49b54bSJia, Chunhui break; 366cc49b54bSJia, Chunhui case FWUpdateTarget::targetME: 367cc49b54bSJia, Chunhui firmware = "ME"; 368cc49b54bSJia, Chunhui buildInfo = 369cc49b54bSJia, Chunhui " major: " + std::to_string(majorRevision) + " minor1: " + 370cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 371cc49b54bSJia, Chunhui " minor2: " + 372cc49b54bSJia, Chunhui std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) + 373cc49b54bSJia, Chunhui " build1: " + 374cc49b54bSJia, Chunhui std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) + 375cc49b54bSJia, Chunhui " build2: " + 376cc49b54bSJia, Chunhui std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16))); 377cc49b54bSJia, Chunhui break; 378cc49b54bSJia, Chunhui case FWUpdateTarget::targetOEMEWS: 379cc49b54bSJia, Chunhui firmware = "EWS"; 380cc49b54bSJia, Chunhui buildInfo = " major: " + std::to_string(majorRevision) + 381cc49b54bSJia, Chunhui " minor: " + 382cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 383cc49b54bSJia, Chunhui " BuildID: " + std::to_string(auxInfo); 384cc49b54bSJia, Chunhui break; 385cc49b54bSJia, Chunhui } 386cc49b54bSJia, Chunhui 387cc49b54bSJia, Chunhui switch (status) 388cc49b54bSJia, Chunhui { 389cc49b54bSJia, Chunhui case 0x0: 390cc49b54bSJia, Chunhui action = "update started"; 391cc49b54bSJia, Chunhui break; 392cc49b54bSJia, Chunhui case 0x1: 393cc49b54bSJia, Chunhui action = "update completed successfully"; 394cc49b54bSJia, Chunhui break; 395cc49b54bSJia, Chunhui case 0x2: 396cc49b54bSJia, Chunhui action = "update failure"; 397cc49b54bSJia, Chunhui break; 398cc49b54bSJia, Chunhui default: 399cc49b54bSJia, Chunhui action = "unknown"; 400cc49b54bSJia, Chunhui break; 401cc49b54bSJia, Chunhui } 402cc49b54bSJia, Chunhui 403cc49b54bSJia, Chunhui std::string message( 404cc49b54bSJia, Chunhui "[firmware update] " + firmware + " instance: " + 405cc49b54bSJia, Chunhui std::to_string((target & targetInstanceMask) >> targetInstanceShift) + 406cc49b54bSJia, Chunhui " status: <" + action + ">" + buildInfo); 407cc49b54bSJia, Chunhui static constexpr const char* redfishMsgId = "FirmwareUpdate"; 408cc49b54bSJia, Chunhui 409cc49b54bSJia, Chunhui sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO, 410cc49b54bSJia, Chunhui "REDFISH_MESSAGE_ID=%s", redfishMsgId, NULL); 411cc49b54bSJia, Chunhui return ipmi::responseSuccess(); 412cc49b54bSJia, Chunhui } 413cc49b54bSJia, Chunhui 41464796041SJason M. Bills ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 41564796041SJason M. Bills ipmi_request_t request, 41664796041SJason M. Bills ipmi_response_t response, 41764796041SJason M. Bills ipmi_data_len_t dataLen, 41864796041SJason M. Bills ipmi_context_t context) 41964796041SJason M. Bills { 42064796041SJason M. Bills SetPowerRestoreDelayReq* data = 42164796041SJason M. Bills reinterpret_cast<SetPowerRestoreDelayReq*>(request); 42264796041SJason M. Bills uint16_t delay = 0; 42364796041SJason M. Bills 42464796041SJason M. Bills if (*dataLen != sizeof(SetPowerRestoreDelayReq)) 42564796041SJason M. Bills { 42664796041SJason M. Bills *dataLen = 0; 42764796041SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 42864796041SJason M. Bills } 42964796041SJason M. Bills delay = data->byteMSB; 43064796041SJason M. Bills delay = (delay << 8) | data->byteLSB; 43164796041SJason M. Bills std::string service = 43264796041SJason M. Bills getService(dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 43364796041SJason M. Bills setDbusProperty(dbus, service, powerRestoreDelayObjPath, 43464796041SJason M. Bills powerRestoreDelayIntf, powerRestoreDelayProp, delay); 43564796041SJason M. Bills *dataLen = 0; 43664796041SJason M. Bills 43764796041SJason M. Bills return IPMI_CC_OK; 43864796041SJason M. Bills } 43964796041SJason M. Bills 44064796041SJason M. Bills ipmi_ret_t ipmiOEMGetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 44164796041SJason M. Bills ipmi_request_t request, 44264796041SJason M. Bills ipmi_response_t response, 44364796041SJason M. Bills ipmi_data_len_t dataLen, 44464796041SJason M. Bills ipmi_context_t context) 44564796041SJason M. Bills { 44664796041SJason M. Bills GetProcessorErrConfigRes* resp = 44764796041SJason M. Bills reinterpret_cast<GetProcessorErrConfigRes*>(response); 44864796041SJason M. Bills 44964796041SJason M. Bills if (*dataLen != 0) 45064796041SJason M. Bills { 45164796041SJason M. Bills *dataLen = 0; 45264796041SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 45364796041SJason M. Bills } 45464796041SJason M. Bills 45564796041SJason M. Bills std::string service = 45664796041SJason M. Bills getService(dbus, processorErrConfigIntf, processorErrConfigObjPath); 45764796041SJason M. Bills Value variant = getDbusProperty(dbus, service, processorErrConfigObjPath, 45864796041SJason M. Bills processorErrConfigIntf, "ResetCfg"); 45964796041SJason M. Bills resp->resetCfg = sdbusplus::message::variant_ns::get<uint8_t>(variant); 46064796041SJason M. Bills 46164796041SJason M. Bills std::vector<uint8_t> caterrStatus; 462bc546679SKuiying Wang sdbusplus::message::variant<std::vector<uint8_t>> message; 46364796041SJason M. Bills 46464796041SJason M. Bills auto method = 46564796041SJason M. Bills dbus.new_method_call(service.c_str(), processorErrConfigObjPath, 46664796041SJason M. Bills "org.freedesktop.DBus.Properties", "Get"); 46764796041SJason M. Bills 46864796041SJason M. Bills method.append(processorErrConfigIntf, "CATERRStatus"); 469bc546679SKuiying Wang auto reply = dbus.call(method); 47064796041SJason M. Bills 47164796041SJason M. Bills try 47264796041SJason M. Bills { 473bc546679SKuiying Wang reply.read(message); 474bc546679SKuiying Wang caterrStatus = 475bc546679SKuiying Wang sdbusplus::message::variant_ns::get<std::vector<uint8_t>>(message); 47664796041SJason M. Bills } 47764796041SJason M. Bills catch (sdbusplus::exception_t&) 47864796041SJason M. Bills { 479bc546679SKuiying Wang phosphor::logging::log<phosphor::logging::level::ERR>( 48064796041SJason M. Bills "ipmiOEMGetProcessorErrConfig: error on dbus", 48164796041SJason M. Bills phosphor::logging::entry("PRORPERTY=CATERRStatus"), 48264796041SJason M. Bills phosphor::logging::entry("PATH=%s", processorErrConfigObjPath), 48364796041SJason M. Bills phosphor::logging::entry("INTERFACE=%s", processorErrConfigIntf)); 48464796041SJason M. Bills return IPMI_CC_UNSPECIFIED_ERROR; 48564796041SJason M. Bills } 48664796041SJason M. Bills 48764796041SJason M. Bills size_t len = 48864796041SJason M. Bills maxCPUNum <= caterrStatus.size() ? maxCPUNum : caterrStatus.size(); 48964796041SJason M. Bills caterrStatus.resize(len); 49064796041SJason M. Bills std::copy(caterrStatus.begin(), caterrStatus.end(), resp->caterrStatus); 49164796041SJason M. Bills *dataLen = sizeof(GetProcessorErrConfigRes); 49264796041SJason M. Bills 49364796041SJason M. Bills return IPMI_CC_OK; 49464796041SJason M. Bills } 49564796041SJason M. Bills 49664796041SJason M. Bills ipmi_ret_t ipmiOEMSetProcessorErrConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 49764796041SJason M. Bills ipmi_request_t request, 49864796041SJason M. Bills ipmi_response_t response, 49964796041SJason M. Bills ipmi_data_len_t dataLen, 50064796041SJason M. Bills ipmi_context_t context) 50164796041SJason M. Bills { 50264796041SJason M. Bills SetProcessorErrConfigReq* req = 50364796041SJason M. Bills reinterpret_cast<SetProcessorErrConfigReq*>(request); 50464796041SJason M. Bills 50564796041SJason M. Bills if (*dataLen != sizeof(SetProcessorErrConfigReq)) 50664796041SJason M. Bills { 50764796041SJason M. Bills *dataLen = 0; 50864796041SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 50964796041SJason M. Bills } 51064796041SJason M. Bills std::string service = 51164796041SJason M. Bills getService(dbus, processorErrConfigIntf, processorErrConfigObjPath); 51264796041SJason M. Bills setDbusProperty(dbus, service, processorErrConfigObjPath, 51364796041SJason M. Bills processorErrConfigIntf, "ResetCfg", req->resetCfg); 51464796041SJason M. Bills 51564796041SJason M. Bills setDbusProperty(dbus, service, processorErrConfigObjPath, 51664796041SJason M. Bills processorErrConfigIntf, "ResetErrorOccurrenceCounts", 51764796041SJason M. Bills req->resetErrorOccurrenceCounts); 51864796041SJason M. Bills *dataLen = 0; 51964796041SJason M. Bills 52064796041SJason M. Bills return IPMI_CC_OK; 52164796041SJason M. Bills } 52264796041SJason M. Bills 523703922d0SYong Li ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 524703922d0SYong Li ipmi_request_t request, 525703922d0SYong Li ipmi_response_t response, 526703922d0SYong Li ipmi_data_len_t dataLen, 527703922d0SYong Li ipmi_context_t context) 528703922d0SYong Li { 529703922d0SYong Li GetOEMShutdownPolicyRes* resp = 530703922d0SYong Li reinterpret_cast<GetOEMShutdownPolicyRes*>(response); 531703922d0SYong Li 532703922d0SYong Li if (*dataLen != 0) 533703922d0SYong Li { 534703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 53545f04988SKuiying Wang "oem_get_shutdown_policy: invalid input len!"); 536703922d0SYong Li *dataLen = 0; 537703922d0SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 538703922d0SYong Li } 539703922d0SYong Li 540703922d0SYong Li *dataLen = 0; 541703922d0SYong Li 542703922d0SYong Li try 543703922d0SYong Li { 544703922d0SYong Li std::string service = 545703922d0SYong Li getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 546703922d0SYong Li Value variant = getDbusProperty(dbus, service, oemShutdownPolicyObjPath, 547703922d0SYong Li oemShutdownPolicyIntf, 548703922d0SYong Li oemShutdownPolicyObjPathProp); 549703922d0SYong Li resp->policy = sdbusplus::message::variant_ns::get<uint8_t>(variant); 550703922d0SYong Li // TODO needs to check if it is multi-node products, 551703922d0SYong Li // policy is only supported on node 3/4 552703922d0SYong Li resp->policySupport = shutdownPolicySupported; 553703922d0SYong Li } 554703922d0SYong Li catch (sdbusplus::exception_t& e) 555703922d0SYong Li { 556703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 557703922d0SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 558703922d0SYong Li } 559703922d0SYong Li 560703922d0SYong Li *dataLen = sizeof(GetOEMShutdownPolicyRes); 561703922d0SYong Li return IPMI_CC_OK; 562703922d0SYong Li } 563703922d0SYong Li 564703922d0SYong Li ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 565703922d0SYong Li ipmi_request_t request, 566703922d0SYong Li ipmi_response_t response, 567703922d0SYong Li ipmi_data_len_t dataLen, 568703922d0SYong Li ipmi_context_t context) 569703922d0SYong Li { 570703922d0SYong Li uint8_t* req = reinterpret_cast<uint8_t*>(request); 571703922d0SYong Li 572703922d0SYong Li // TODO needs to check if it is multi-node products, 573703922d0SYong Li // policy is only supported on node 3/4 574703922d0SYong Li if (*dataLen != 1) 575703922d0SYong Li { 576703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 577703922d0SYong Li "oem_set_shutdown_policy: invalid input len!"); 578703922d0SYong Li *dataLen = 0; 579703922d0SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 580703922d0SYong Li } 581703922d0SYong Li 582703922d0SYong Li *dataLen = 0; 583703922d0SYong Li if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT)) 584703922d0SYong Li { 585703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 586703922d0SYong Li "oem_set_shutdown_policy: invalid input!"); 587703922d0SYong Li return IPMI_CC_INVALID_FIELD_REQUEST; 588703922d0SYong Li } 589703922d0SYong Li 590703922d0SYong Li try 591703922d0SYong Li { 592703922d0SYong Li std::string service = 593703922d0SYong Li getService(dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 594703922d0SYong Li setDbusProperty(dbus, service, oemShutdownPolicyObjPath, 595703922d0SYong Li oemShutdownPolicyIntf, oemShutdownPolicyObjPathProp, 596703922d0SYong Li *req); 597703922d0SYong Li } 598703922d0SYong Li catch (sdbusplus::exception_t& e) 599703922d0SYong Li { 600703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 601703922d0SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 602703922d0SYong Li } 603703922d0SYong Li 604703922d0SYong Li return IPMI_CC_OK; 605703922d0SYong Li } 606703922d0SYong Li 607d509eb91SSuryakanth Sekar /** @brief implementation for check the DHCP or not in IPv4 608d509eb91SSuryakanth Sekar * @param[in] Channel - Channel number 609d509eb91SSuryakanth Sekar * @returns true or false. 610d509eb91SSuryakanth Sekar */ 611d509eb91SSuryakanth Sekar static bool isDHCPEnabled(uint8_t Channel) 612d509eb91SSuryakanth Sekar { 613d509eb91SSuryakanth Sekar try 614d509eb91SSuryakanth Sekar { 615d509eb91SSuryakanth Sekar auto ethdevice = getChannelName(Channel); 616d509eb91SSuryakanth Sekar if (ethdevice.empty()) 617d509eb91SSuryakanth Sekar { 618d509eb91SSuryakanth Sekar return false; 619d509eb91SSuryakanth Sekar } 620d509eb91SSuryakanth Sekar auto ethIP = ethdevice + "/ipv4"; 621d509eb91SSuryakanth Sekar auto ethernetObj = 622d509eb91SSuryakanth Sekar getDbusObject(dbus, networkIPIntf, networkRoot, ethIP); 623d509eb91SSuryakanth Sekar auto value = getDbusProperty(dbus, networkService, ethernetObj.first, 624d509eb91SSuryakanth Sekar networkIPIntf, "Origin"); 625d509eb91SSuryakanth Sekar if (sdbusplus::message::variant_ns::get<std::string>(value) == 626d509eb91SSuryakanth Sekar "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 627d509eb91SSuryakanth Sekar { 628d509eb91SSuryakanth Sekar return true; 629d509eb91SSuryakanth Sekar } 630d509eb91SSuryakanth Sekar else 631d509eb91SSuryakanth Sekar { 632d509eb91SSuryakanth Sekar return false; 633d509eb91SSuryakanth Sekar } 634d509eb91SSuryakanth Sekar } 635d509eb91SSuryakanth Sekar catch (sdbusplus::exception_t& e) 636d509eb91SSuryakanth Sekar { 637d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 638d509eb91SSuryakanth Sekar return true; 639d509eb91SSuryakanth Sekar } 640d509eb91SSuryakanth Sekar } 641d509eb91SSuryakanth Sekar 642d509eb91SSuryakanth Sekar /** @brief implementes for check the DHCP or not in IPv6 643d509eb91SSuryakanth Sekar * @param[in] Channel - Channel number 644d509eb91SSuryakanth Sekar * @returns true or false. 645d509eb91SSuryakanth Sekar */ 646d509eb91SSuryakanth Sekar static bool isDHCPIPv6Enabled(uint8_t Channel) 647d509eb91SSuryakanth Sekar { 648d509eb91SSuryakanth Sekar 649d509eb91SSuryakanth Sekar try 650d509eb91SSuryakanth Sekar { 651d509eb91SSuryakanth Sekar auto ethdevice = getChannelName(Channel); 652d509eb91SSuryakanth Sekar if (ethdevice.empty()) 653d509eb91SSuryakanth Sekar { 654d509eb91SSuryakanth Sekar return false; 655d509eb91SSuryakanth Sekar } 656d509eb91SSuryakanth Sekar auto ethIP = ethdevice + "/ipv6"; 657d509eb91SSuryakanth Sekar auto objectInfo = 658d509eb91SSuryakanth Sekar getDbusObject(dbus, networkIPIntf, networkRoot, ethIP); 659d509eb91SSuryakanth Sekar auto properties = getAllDbusProperties(dbus, objectInfo.second, 660d509eb91SSuryakanth Sekar objectInfo.first, networkIPIntf); 661d509eb91SSuryakanth Sekar if (sdbusplus::message::variant_ns::get<std::string>( 662d509eb91SSuryakanth Sekar properties["Origin"]) == 663d509eb91SSuryakanth Sekar "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 664d509eb91SSuryakanth Sekar { 665d509eb91SSuryakanth Sekar return true; 666d509eb91SSuryakanth Sekar } 667d509eb91SSuryakanth Sekar else 668d509eb91SSuryakanth Sekar { 669d509eb91SSuryakanth Sekar return false; 670d509eb91SSuryakanth Sekar } 671d509eb91SSuryakanth Sekar } 672d509eb91SSuryakanth Sekar catch (sdbusplus::exception_t& e) 673d509eb91SSuryakanth Sekar { 674d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 675d509eb91SSuryakanth Sekar return true; 676d509eb91SSuryakanth Sekar } 677d509eb91SSuryakanth Sekar } 678d509eb91SSuryakanth Sekar 679d509eb91SSuryakanth Sekar /** @brief implementes the creating of default new user 680d509eb91SSuryakanth Sekar * @param[in] userName - new username in 16 bytes. 681d509eb91SSuryakanth Sekar * @param[in] userPassword - new password in 20 bytes 682d509eb91SSuryakanth Sekar * @returns ipmi completion code. 683d509eb91SSuryakanth Sekar */ 684d509eb91SSuryakanth Sekar ipmi::RspType<> ipmiOEMSetUser2Activation( 685d509eb91SSuryakanth Sekar std::array<uint8_t, ipmi::ipmiMaxUserName>& userName, 686d509eb91SSuryakanth Sekar std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword) 687d509eb91SSuryakanth Sekar { 688d509eb91SSuryakanth Sekar bool userState = false; 689d509eb91SSuryakanth Sekar // Check for System Interface not exist and LAN should be static 690d509eb91SSuryakanth Sekar for (uint8_t channel = 0; channel < maxIpmiChannels; channel++) 691d509eb91SSuryakanth Sekar { 692d509eb91SSuryakanth Sekar ChannelInfo chInfo; 693d509eb91SSuryakanth Sekar try 694d509eb91SSuryakanth Sekar { 695d509eb91SSuryakanth Sekar getChannelInfo(channel, chInfo); 696d509eb91SSuryakanth Sekar } 697d509eb91SSuryakanth Sekar catch (sdbusplus::exception_t& e) 698d509eb91SSuryakanth Sekar { 699d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 700d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: Failed to get Channel Info", 701d509eb91SSuryakanth Sekar phosphor::logging::entry("MSG: %s", e.description())); 702d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccUnspecifiedError); 703d509eb91SSuryakanth Sekar } 704d509eb91SSuryakanth Sekar if (chInfo.mediumType == 705d509eb91SSuryakanth Sekar static_cast<uint8_t>(EChannelMediumType::systemInterface)) 706d509eb91SSuryakanth Sekar { 707d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 708d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: system interface exist ."); 709d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 710d509eb91SSuryakanth Sekar } 711d509eb91SSuryakanth Sekar else 712d509eb91SSuryakanth Sekar { 713d509eb91SSuryakanth Sekar 714d509eb91SSuryakanth Sekar if (chInfo.mediumType == 715d509eb91SSuryakanth Sekar static_cast<uint8_t>(EChannelMediumType::lan8032)) 716d509eb91SSuryakanth Sekar { 717d509eb91SSuryakanth Sekar if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel)) 718d509eb91SSuryakanth Sekar { 719d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 720d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: DHCP enabled ."); 721d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 722d509eb91SSuryakanth Sekar } 723d509eb91SSuryakanth Sekar } 724d509eb91SSuryakanth Sekar } 725d509eb91SSuryakanth Sekar } 726d509eb91SSuryakanth Sekar uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0; 727d509eb91SSuryakanth Sekar if (ipmi::ccSuccess == 728d509eb91SSuryakanth Sekar ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers)) 729d509eb91SSuryakanth Sekar { 730d509eb91SSuryakanth Sekar if (enabledUsers > 1) 731d509eb91SSuryakanth Sekar { 732d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 733d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: more than one user is enabled."); 734d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 735d509eb91SSuryakanth Sekar } 736d509eb91SSuryakanth Sekar // Check the user 2 is enabled or not 737d509eb91SSuryakanth Sekar ipmiUserCheckEnabled(ipmiDefaultUserId, userState); 738d509eb91SSuryakanth Sekar if (userState == true) 739d509eb91SSuryakanth Sekar { 740d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 741d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: user 2 already enabled ."); 742d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 743d509eb91SSuryakanth Sekar } 744d509eb91SSuryakanth Sekar } 745d509eb91SSuryakanth Sekar else 746d509eb91SSuryakanth Sekar { 747d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccUnspecifiedError); 748d509eb91SSuryakanth Sekar } 749d509eb91SSuryakanth Sekar 750d509eb91SSuryakanth Sekar #if BYTE_ORDER == LITTLE_ENDIAN 751d509eb91SSuryakanth Sekar PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0}; 752d509eb91SSuryakanth Sekar #endif 753d509eb91SSuryakanth Sekar #if BYTE_ORDER == BIG_ENDIAN 754d509eb91SSuryakanth Sekar PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN}; 755d509eb91SSuryakanth Sekar #endif 756d509eb91SSuryakanth Sekar 757d509eb91SSuryakanth Sekar if (ipmi::ccSuccess == 758d509eb91SSuryakanth Sekar ipmiUserSetUserName(ipmiDefaultUserId, 759d509eb91SSuryakanth Sekar reinterpret_cast<const char*>(userName.data()))) 760d509eb91SSuryakanth Sekar { 761d509eb91SSuryakanth Sekar if (ipmi::ccSuccess == 762d509eb91SSuryakanth Sekar ipmiUserSetUserPassword( 763d509eb91SSuryakanth Sekar ipmiDefaultUserId, 764d509eb91SSuryakanth Sekar reinterpret_cast<const char*>(userPassword.data()))) 765d509eb91SSuryakanth Sekar { 766d509eb91SSuryakanth Sekar if (ipmi::ccSuccess == 767d509eb91SSuryakanth Sekar ipmiUserSetPrivilegeAccess( 768d509eb91SSuryakanth Sekar ipmiDefaultUserId, 769d509eb91SSuryakanth Sekar static_cast<uint8_t>(ipmi::EChannelID::chanLan1), 770d509eb91SSuryakanth Sekar privAccess, true)) 771d509eb91SSuryakanth Sekar { 772d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::INFO>( 773d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: user created successfully "); 774d509eb91SSuryakanth Sekar return ipmi::responseSuccess(); 775d509eb91SSuryakanth Sekar } 776d509eb91SSuryakanth Sekar } 777d509eb91SSuryakanth Sekar // we need to delete the default user id which added in this command as 778d509eb91SSuryakanth Sekar // password / priv setting is failed. 779d509eb91SSuryakanth Sekar ipmiUserSetUserName(ipmiDefaultUserId, ""); 780d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 781d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: password / priv setting is failed."); 782d509eb91SSuryakanth Sekar } 783d509eb91SSuryakanth Sekar else 784d509eb91SSuryakanth Sekar { 785d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 786d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: Setting username failed."); 787d509eb91SSuryakanth Sekar } 788d509eb91SSuryakanth Sekar 789d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 790d509eb91SSuryakanth Sekar } 791d509eb91SSuryakanth Sekar 79245f04988SKuiying Wang namespace ledAction 79345f04988SKuiying Wang { 79445f04988SKuiying Wang using namespace sdbusplus::xyz::openbmc_project::Led::server; 79545f04988SKuiying Wang std::map<Physical::Action, uint8_t> actionDbusToIpmi = { 79645f04988SKuiying Wang {Physical::Action::Off, 0x00}, 79745f04988SKuiying Wang {Physical::Action::On, 0x10}, 79845f04988SKuiying Wang {Physical::Action::Blink, 0x01}}; 79945f04988SKuiying Wang 80045f04988SKuiying Wang std::map<uint8_t, std::string> offsetObjPath = { 80145f04988SKuiying Wang {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}}; 80245f04988SKuiying Wang 80345f04988SKuiying Wang } // namespace ledAction 80445f04988SKuiying Wang 80545f04988SKuiying Wang int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf, 80645f04988SKuiying Wang const std::string& objPath, uint8_t& state) 80745f04988SKuiying Wang { 80845f04988SKuiying Wang try 80945f04988SKuiying Wang { 81045f04988SKuiying Wang std::string service = getService(bus, intf, objPath); 81145f04988SKuiying Wang Value stateValue = 81245f04988SKuiying Wang getDbusProperty(bus, service, objPath, intf, "State"); 81345f04988SKuiying Wang std::string strState = 81445f04988SKuiying Wang sdbusplus::message::variant_ns::get<std::string>(stateValue); 81545f04988SKuiying Wang state = ledAction::actionDbusToIpmi.at( 81645f04988SKuiying Wang sdbusplus::xyz::openbmc_project::Led::server::Physical:: 81745f04988SKuiying Wang convertActionFromString(strState)); 81845f04988SKuiying Wang } 81945f04988SKuiying Wang catch (sdbusplus::exception::SdBusError& e) 82045f04988SKuiying Wang { 82145f04988SKuiying Wang phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 82245f04988SKuiying Wang return -1; 82345f04988SKuiying Wang } 82445f04988SKuiying Wang return 0; 82545f04988SKuiying Wang } 82645f04988SKuiying Wang 82745f04988SKuiying Wang ipmi_ret_t ipmiOEMGetLEDStatus(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 82845f04988SKuiying Wang ipmi_request_t request, ipmi_response_t response, 82945f04988SKuiying Wang ipmi_data_len_t dataLen, ipmi_context_t context) 83045f04988SKuiying Wang { 83145f04988SKuiying Wang uint8_t* resp = reinterpret_cast<uint8_t*>(response); 83245f04988SKuiying Wang // LED Status 83345f04988SKuiying Wang //[1:0] = Reserved 83445f04988SKuiying Wang //[3:2] = Status(Amber) 83545f04988SKuiying Wang //[5:4] = Status(Green) 83645f04988SKuiying Wang //[7:6] = System Identify 83745f04988SKuiying Wang // Status definitions: 83845f04988SKuiying Wang // 00b = Off 83945f04988SKuiying Wang // 01b = Blink 84045f04988SKuiying Wang // 10b = On 84145f04988SKuiying Wang // 11b = invalid 84245f04988SKuiying Wang if (*dataLen != 0) 84345f04988SKuiying Wang { 84445f04988SKuiying Wang phosphor::logging::log<phosphor::logging::level::ERR>( 84545f04988SKuiying Wang "oem_get_led_status: invalid input len!"); 84645f04988SKuiying Wang *dataLen = 0; 84745f04988SKuiying Wang return IPMI_CC_REQ_DATA_LEN_INVALID; 84845f04988SKuiying Wang } 84945f04988SKuiying Wang 85045f04988SKuiying Wang phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status"); 85145f04988SKuiying Wang *resp = 0; 85245f04988SKuiying Wang *dataLen = 0; 85345f04988SKuiying Wang for (auto it = ledAction::offsetObjPath.begin(); 85445f04988SKuiying Wang it != ledAction::offsetObjPath.end(); ++it) 85545f04988SKuiying Wang { 85645f04988SKuiying Wang uint8_t state = 0; 85745f04988SKuiying Wang if (-1 == getLEDState(dbus, ledIntf, it->second, state)) 85845f04988SKuiying Wang { 85945f04988SKuiying Wang phosphor::logging::log<phosphor::logging::level::ERR>( 86045f04988SKuiying Wang "oem_get_led_status: fail to get ID LED status!"); 86145f04988SKuiying Wang return IPMI_CC_UNSPECIFIED_ERROR; 86245f04988SKuiying Wang } 86345f04988SKuiying Wang *resp |= state << it->first; 86445f04988SKuiying Wang } 86545f04988SKuiying Wang 86645f04988SKuiying Wang *dataLen = sizeof(*resp); 86745f04988SKuiying Wang return IPMI_CC_OK; 86845f04988SKuiying Wang } 86945f04988SKuiying Wang 87023737fe3SYong Li ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 87123737fe3SYong Li ipmi_request_t request, 87223737fe3SYong Li ipmi_response_t response, 87323737fe3SYong Li ipmi_data_len_t dataLen, 87423737fe3SYong Li ipmi_context_t context) 87523737fe3SYong Li { 87623737fe3SYong Li CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request); 87723737fe3SYong Li uint8_t* resp = reinterpret_cast<uint8_t*>(response); 87823737fe3SYong Li 87923737fe3SYong Li if (*dataLen == 0) 88023737fe3SYong Li { 88123737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 88223737fe3SYong Li "CfgHostSerial: invalid input len!", 88323737fe3SYong Li phosphor::logging::entry("LEN=%d", *dataLen)); 88423737fe3SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 88523737fe3SYong Li } 88623737fe3SYong Li 88723737fe3SYong Li switch (req->command) 88823737fe3SYong Li { 88923737fe3SYong Li case getHostSerialCfgCmd: 89023737fe3SYong Li { 89123737fe3SYong Li if (*dataLen != 1) 89223737fe3SYong Li { 89323737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 89423737fe3SYong Li "CfgHostSerial: invalid input len!"); 89523737fe3SYong Li *dataLen = 0; 89623737fe3SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 89723737fe3SYong Li } 89823737fe3SYong Li 89923737fe3SYong Li *dataLen = 0; 90023737fe3SYong Li 90123737fe3SYong Li boost::process::ipstream is; 90223737fe3SYong Li std::vector<std::string> data; 90323737fe3SYong Li std::string line; 90423737fe3SYong Li boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName, 90523737fe3SYong Li boost::process::std_out > is); 90623737fe3SYong Li 90723737fe3SYong Li while (c1.running() && std::getline(is, line) && !line.empty()) 90823737fe3SYong Li { 90923737fe3SYong Li data.push_back(line); 91023737fe3SYong Li } 91123737fe3SYong Li 91223737fe3SYong Li c1.wait(); 91323737fe3SYong Li if (c1.exit_code()) 91423737fe3SYong Li { 91523737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 91623737fe3SYong Li "CfgHostSerial:: error on execute", 91723737fe3SYong Li phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd)); 91823737fe3SYong Li // Using the default value 91923737fe3SYong Li *resp = 0; 92023737fe3SYong Li } 92123737fe3SYong Li else 92223737fe3SYong Li { 92323737fe3SYong Li if (data.size() != 1) 92423737fe3SYong Li { 92523737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 92623737fe3SYong Li "CfgHostSerial:: error on read env"); 92723737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 92823737fe3SYong Li } 92923737fe3SYong Li try 93023737fe3SYong Li { 93123737fe3SYong Li unsigned long tmp = std::stoul(data[0]); 93223737fe3SYong Li if (tmp > std::numeric_limits<uint8_t>::max()) 93323737fe3SYong Li { 93423737fe3SYong Li throw std::out_of_range("Out of range"); 93523737fe3SYong Li } 93623737fe3SYong Li *resp = static_cast<uint8_t>(tmp); 93723737fe3SYong Li } 93823737fe3SYong Li catch (const std::invalid_argument& e) 93923737fe3SYong Li { 94023737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 94123737fe3SYong Li "invalid config ", 94223737fe3SYong Li phosphor::logging::entry("ERR=%s", e.what())); 94323737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 94423737fe3SYong Li } 94523737fe3SYong Li catch (const std::out_of_range& e) 94623737fe3SYong Li { 94723737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 94823737fe3SYong Li "out_of_range config ", 94923737fe3SYong Li phosphor::logging::entry("ERR=%s", e.what())); 95023737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 95123737fe3SYong Li } 95223737fe3SYong Li } 95323737fe3SYong Li 95423737fe3SYong Li *dataLen = 1; 95523737fe3SYong Li break; 95623737fe3SYong Li } 95723737fe3SYong Li case setHostSerialCfgCmd: 95823737fe3SYong Li { 95923737fe3SYong Li if (*dataLen != sizeof(CfgHostSerialReq)) 96023737fe3SYong Li { 96123737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 96223737fe3SYong Li "CfgHostSerial: invalid input len!"); 96323737fe3SYong Li *dataLen = 0; 96423737fe3SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 96523737fe3SYong Li } 96623737fe3SYong Li 96723737fe3SYong Li *dataLen = 0; 96823737fe3SYong Li 96923737fe3SYong Li if (req->parameter > HostSerialCfgParamMax) 97023737fe3SYong Li { 97123737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 97223737fe3SYong Li "CfgHostSerial: invalid input!"); 97323737fe3SYong Li return IPMI_CC_INVALID_FIELD_REQUEST; 97423737fe3SYong Li } 97523737fe3SYong Li 97623737fe3SYong Li boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName, 97723737fe3SYong Li std::to_string(req->parameter)); 97823737fe3SYong Li 97923737fe3SYong Li c1.wait(); 98023737fe3SYong Li if (c1.exit_code()) 98123737fe3SYong Li { 98223737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 98323737fe3SYong Li "CfgHostSerial:: error on execute", 98423737fe3SYong Li phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd)); 98523737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 98623737fe3SYong Li } 98723737fe3SYong Li break; 98823737fe3SYong Li } 98923737fe3SYong Li default: 99023737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 99123737fe3SYong Li "CfgHostSerial: invalid input!"); 99223737fe3SYong Li *dataLen = 0; 99323737fe3SYong Li return IPMI_CC_INVALID_FIELD_REQUEST; 99423737fe3SYong Li } 99523737fe3SYong Li 99623737fe3SYong Li return IPMI_CC_OK; 99723737fe3SYong Li } 99823737fe3SYong Li 99991244a6aSJames Feist constexpr const char* thermalModeInterface = 100091244a6aSJames Feist "xyz.openbmc_project.Control.ThermalMode"; 100191244a6aSJames Feist constexpr const char* thermalModePath = 100291244a6aSJames Feist "/xyz/openbmc_project/control/thermal_mode"; 100391244a6aSJames Feist 100491244a6aSJames Feist bool getFanProfileInterface( 100591244a6aSJames Feist sdbusplus::bus::bus& bus, 100691244a6aSJames Feist boost::container::flat_map< 100791244a6aSJames Feist std::string, std::variant<std::vector<std::string>, std::string>>& resp) 100891244a6aSJames Feist { 100991244a6aSJames Feist auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF, 101091244a6aSJames Feist "GetAll"); 101191244a6aSJames Feist call.append(thermalModeInterface); 101291244a6aSJames Feist try 101391244a6aSJames Feist { 101491244a6aSJames Feist auto data = bus.call(call); 101591244a6aSJames Feist data.read(resp); 101691244a6aSJames Feist } 101791244a6aSJames Feist catch (sdbusplus::exception_t& e) 101891244a6aSJames Feist { 101991244a6aSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 102091244a6aSJames Feist "getFanProfileInterface: can't get thermal mode!", 102191244a6aSJames Feist phosphor::logging::entry("ERR=%s", e.what())); 102291244a6aSJames Feist return false; 102391244a6aSJames Feist } 102491244a6aSJames Feist return true; 102591244a6aSJames Feist } 102691244a6aSJames Feist 102791244a6aSJames Feist ipmi_ret_t ipmiOEMSetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 102891244a6aSJames Feist ipmi_request_t request, ipmi_response_t response, 102991244a6aSJames Feist ipmi_data_len_t dataLen, ipmi_context_t context) 103091244a6aSJames Feist { 103191244a6aSJames Feist 103291244a6aSJames Feist if (*dataLen < 2 || *dataLen > 7) 103391244a6aSJames Feist { 103491244a6aSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 103591244a6aSJames Feist "ipmiOEMSetFanConfig: invalid input len!"); 103691244a6aSJames Feist *dataLen = 0; 103791244a6aSJames Feist return IPMI_CC_REQ_DATA_LEN_INVALID; 103891244a6aSJames Feist } 103991244a6aSJames Feist 104091244a6aSJames Feist // todo: tell bios to only send first 2 bytes 104191244a6aSJames Feist 104291244a6aSJames Feist SetFanConfigReq* req = reinterpret_cast<SetFanConfigReq*>(request); 104391244a6aSJames Feist boost::container::flat_map< 104491244a6aSJames Feist std::string, std::variant<std::vector<std::string>, std::string>> 104591244a6aSJames Feist profileData; 104691244a6aSJames Feist if (!getFanProfileInterface(dbus, profileData)) 104791244a6aSJames Feist { 104891244a6aSJames Feist return IPMI_CC_UNSPECIFIED_ERROR; 104991244a6aSJames Feist } 105091244a6aSJames Feist 105191244a6aSJames Feist std::vector<std::string>* supported = 105291244a6aSJames Feist std::get_if<std::vector<std::string>>(&profileData["Supported"]); 105391244a6aSJames Feist if (supported == nullptr) 105491244a6aSJames Feist { 105591244a6aSJames Feist return IPMI_CC_INVALID_FIELD_REQUEST; 105691244a6aSJames Feist } 105791244a6aSJames Feist std::string mode; 105891244a6aSJames Feist if (req->flags & 105991244a6aSJames Feist (1 << static_cast<uint8_t>(setFanProfileFlags::setPerfAcousMode))) 106091244a6aSJames Feist { 106191244a6aSJames Feist bool performanceMode = 106291244a6aSJames Feist (req->flags & (1 << static_cast<uint8_t>( 106391244a6aSJames Feist setFanProfileFlags::performAcousSelect))) > 0; 106491244a6aSJames Feist 106591244a6aSJames Feist if (performanceMode) 106691244a6aSJames Feist { 106791244a6aSJames Feist 106891244a6aSJames Feist if (std::find(supported->begin(), supported->end(), 106991244a6aSJames Feist "Performance") != supported->end()) 107091244a6aSJames Feist { 107191244a6aSJames Feist mode = "Performance"; 107291244a6aSJames Feist } 107391244a6aSJames Feist } 107491244a6aSJames Feist else 107591244a6aSJames Feist { 107691244a6aSJames Feist 107791244a6aSJames Feist if (std::find(supported->begin(), supported->end(), "Acoustic") != 107891244a6aSJames Feist supported->end()) 107991244a6aSJames Feist { 108091244a6aSJames Feist mode = "Acoustic"; 108191244a6aSJames Feist } 108291244a6aSJames Feist } 108391244a6aSJames Feist if (mode.empty()) 108491244a6aSJames Feist { 108591244a6aSJames Feist return IPMI_CC_INVALID_FIELD_REQUEST; 108691244a6aSJames Feist } 108791244a6aSJames Feist setDbusProperty(dbus, settingsBusName, thermalModePath, 108891244a6aSJames Feist thermalModeInterface, "Current", mode); 108991244a6aSJames Feist } 109091244a6aSJames Feist 109191244a6aSJames Feist return IPMI_CC_OK; 109291244a6aSJames Feist } 109391244a6aSJames Feist 109491244a6aSJames Feist ipmi_ret_t ipmiOEMGetFanConfig(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 109591244a6aSJames Feist ipmi_request_t request, ipmi_response_t response, 109691244a6aSJames Feist ipmi_data_len_t dataLen, ipmi_context_t context) 109791244a6aSJames Feist { 109891244a6aSJames Feist 109991244a6aSJames Feist if (*dataLen > 1) 110091244a6aSJames Feist { 110191244a6aSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 110291244a6aSJames Feist "ipmiOEMGetFanConfig: invalid input len!"); 110391244a6aSJames Feist *dataLen = 0; 110491244a6aSJames Feist return IPMI_CC_REQ_DATA_LEN_INVALID; 110591244a6aSJames Feist } 110691244a6aSJames Feist 110791244a6aSJames Feist // todo: talk to bios about needing less information 110891244a6aSJames Feist 110991244a6aSJames Feist GetFanConfigResp* resp = reinterpret_cast<GetFanConfigResp*>(response); 111091244a6aSJames Feist *dataLen = sizeof(GetFanConfigResp); 111191244a6aSJames Feist 111291244a6aSJames Feist boost::container::flat_map< 111391244a6aSJames Feist std::string, std::variant<std::vector<std::string>, std::string>> 111491244a6aSJames Feist profileData; 111591244a6aSJames Feist 111691244a6aSJames Feist if (!getFanProfileInterface(dbus, profileData)) 111791244a6aSJames Feist { 111891244a6aSJames Feist return IPMI_CC_UNSPECIFIED_ERROR; 111991244a6aSJames Feist } 112091244a6aSJames Feist 112191244a6aSJames Feist std::string* current = std::get_if<std::string>(&profileData["Current"]); 112291244a6aSJames Feist 112391244a6aSJames Feist if (current == nullptr) 112491244a6aSJames Feist { 112591244a6aSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 112691244a6aSJames Feist "ipmiOEMGetFanConfig: can't get current mode!"); 112791244a6aSJames Feist return IPMI_CC_UNSPECIFIED_ERROR; 112891244a6aSJames Feist } 112991244a6aSJames Feist bool performance = (*current == "Performance"); 113091244a6aSJames Feist 113191244a6aSJames Feist if (performance) 113291244a6aSJames Feist { 113391244a6aSJames Feist resp->flags |= 1 << 2; 113491244a6aSJames Feist } 113591244a6aSJames Feist 113691244a6aSJames Feist return IPMI_CC_OK; 113791244a6aSJames Feist } 113891244a6aSJames Feist 11395f957cafSJames Feist constexpr const char* cfmLimitSettingPath = 11405f957cafSJames Feist "/xyz/openbmc_project/control/cfm_limit"; 11415f957cafSJames Feist constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit"; 1142faa4f223SJames Feist constexpr const size_t legacyExitAirSensorNumber = 0x2e; 1143*acc8a4ebSJames Feist constexpr const char* pidConfigurationIface = 1144*acc8a4ebSJames Feist "xyz.openbmc_project.Configuration.Pid"; 1145faa4f223SJames Feist 1146faa4f223SJames Feist static std::string getExitAirConfigPath() 1147faa4f223SJames Feist { 1148faa4f223SJames Feist 1149faa4f223SJames Feist auto method = 1150faa4f223SJames Feist dbus.new_method_call("xyz.openbmc_project.ObjectMapper", 1151faa4f223SJames Feist "/xyz/openbmc_project/object_mapper", 1152faa4f223SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1153faa4f223SJames Feist 1154*acc8a4ebSJames Feist method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1155faa4f223SJames Feist std::string path; 1156faa4f223SJames Feist GetSubTreeType resp; 1157faa4f223SJames Feist try 1158faa4f223SJames Feist { 1159faa4f223SJames Feist auto reply = dbus.call(method); 1160faa4f223SJames Feist reply.read(resp); 1161faa4f223SJames Feist } 1162faa4f223SJames Feist catch (sdbusplus::exception_t&) 1163faa4f223SJames Feist { 1164faa4f223SJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1165faa4f223SJames Feist "ipmiOEMGetFscParameter: mapper error"); 1166faa4f223SJames Feist }; 1167faa4f223SJames Feist auto config = std::find_if(resp.begin(), resp.end(), [](const auto& pair) { 1168faa4f223SJames Feist return pair.first.find("Exit_Air") != std::string::npos; 1169faa4f223SJames Feist }); 1170faa4f223SJames Feist if (config != resp.end()) 1171faa4f223SJames Feist { 1172faa4f223SJames Feist path = std::move(config->first); 1173faa4f223SJames Feist } 1174faa4f223SJames Feist return path; 1175faa4f223SJames Feist } 11765f957cafSJames Feist 1177*acc8a4ebSJames Feist // flat map to make alphabetical 1178*acc8a4ebSJames Feist static boost::container::flat_map<std::string, PropertyMap> getPidConfigs() 1179*acc8a4ebSJames Feist { 1180*acc8a4ebSJames Feist boost::container::flat_map<std::string, PropertyMap> ret; 1181*acc8a4ebSJames Feist auto method = 1182*acc8a4ebSJames Feist dbus.new_method_call("xyz.openbmc_project.ObjectMapper", 1183*acc8a4ebSJames Feist "/xyz/openbmc_project/object_mapper", 1184*acc8a4ebSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1185*acc8a4ebSJames Feist 1186*acc8a4ebSJames Feist method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1187*acc8a4ebSJames Feist GetSubTreeType resp; 1188*acc8a4ebSJames Feist 1189*acc8a4ebSJames Feist try 1190*acc8a4ebSJames Feist { 1191*acc8a4ebSJames Feist auto reply = dbus.call(method); 1192*acc8a4ebSJames Feist reply.read(resp); 1193*acc8a4ebSJames Feist } 1194*acc8a4ebSJames Feist catch (sdbusplus::exception_t&) 1195*acc8a4ebSJames Feist { 1196*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1197*acc8a4ebSJames Feist "getFanConfigPaths: mapper error"); 1198*acc8a4ebSJames Feist }; 1199*acc8a4ebSJames Feist for (const auto& [path, objects] : resp) 1200*acc8a4ebSJames Feist { 1201*acc8a4ebSJames Feist if (objects.empty()) 1202*acc8a4ebSJames Feist { 1203*acc8a4ebSJames Feist continue; // should be impossible 1204*acc8a4ebSJames Feist } 1205*acc8a4ebSJames Feist ret.emplace(path, getAllDbusProperties(dbus, objects[0].first, path, 1206*acc8a4ebSJames Feist pidConfigurationIface)); 1207*acc8a4ebSJames Feist } 1208*acc8a4ebSJames Feist return ret; 1209*acc8a4ebSJames Feist } 1210*acc8a4ebSJames Feist 1211*acc8a4ebSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void) 1212*acc8a4ebSJames Feist { 1213*acc8a4ebSJames Feist boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1214*acc8a4ebSJames Feist if (data.empty()) 1215*acc8a4ebSJames Feist { 1216*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1217*acc8a4ebSJames Feist } 1218*acc8a4ebSJames Feist uint8_t minOffset = std::numeric_limits<uint8_t>::max(); 1219*acc8a4ebSJames Feist for (const auto& [_, pid] : data) 1220*acc8a4ebSJames Feist { 1221*acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1222*acc8a4ebSJames Feist if (findClass == pid.end()) 1223*acc8a4ebSJames Feist { 1224*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1225*acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 1226*acc8a4ebSJames Feist "configurations"); 1227*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1228*acc8a4ebSJames Feist } 1229*acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1230*acc8a4ebSJames Feist if (type == "fan") 1231*acc8a4ebSJames Feist { 1232*acc8a4ebSJames Feist auto findOutLimit = pid.find("OutLimitMin"); 1233*acc8a4ebSJames Feist if (findOutLimit == pid.end()) 1234*acc8a4ebSJames Feist { 1235*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1236*acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 1237*acc8a4ebSJames Feist "configurations"); 1238*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1239*acc8a4ebSJames Feist } 1240*acc8a4ebSJames Feist // get the min out of all the offsets 1241*acc8a4ebSJames Feist minOffset = std::min( 1242*acc8a4ebSJames Feist minOffset, 1243*acc8a4ebSJames Feist static_cast<uint8_t>(std::get<double>(findOutLimit->second))); 1244*acc8a4ebSJames Feist } 1245*acc8a4ebSJames Feist } 1246*acc8a4ebSJames Feist if (minOffset == std::numeric_limits<uint8_t>::max()) 1247*acc8a4ebSJames Feist { 1248*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1249*acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found no fan configurations!"); 1250*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1251*acc8a4ebSJames Feist } 1252*acc8a4ebSJames Feist 1253*acc8a4ebSJames Feist return ipmi::responseSuccess(minOffset); 1254*acc8a4ebSJames Feist } 1255*acc8a4ebSJames Feist 1256*acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset) 1257*acc8a4ebSJames Feist { 1258*acc8a4ebSJames Feist boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1259*acc8a4ebSJames Feist if (data.empty()) 1260*acc8a4ebSJames Feist { 1261*acc8a4ebSJames Feist 1262*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1263*acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: found no pid configurations!"); 1264*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1265*acc8a4ebSJames Feist } 1266*acc8a4ebSJames Feist 1267*acc8a4ebSJames Feist bool found = false; 1268*acc8a4ebSJames Feist for (const auto& [path, pid] : data) 1269*acc8a4ebSJames Feist { 1270*acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1271*acc8a4ebSJames Feist if (findClass == pid.end()) 1272*acc8a4ebSJames Feist { 1273*acc8a4ebSJames Feist 1274*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1275*acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: found illegal pid " 1276*acc8a4ebSJames Feist "configurations"); 1277*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1278*acc8a4ebSJames Feist } 1279*acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1280*acc8a4ebSJames Feist if (type == "fan") 1281*acc8a4ebSJames Feist { 1282*acc8a4ebSJames Feist auto findOutLimit = pid.find("OutLimitMin"); 1283*acc8a4ebSJames Feist if (findOutLimit == pid.end()) 1284*acc8a4ebSJames Feist { 1285*acc8a4ebSJames Feist 1286*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1287*acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: found illegal pid " 1288*acc8a4ebSJames Feist "configurations"); 1289*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1290*acc8a4ebSJames Feist } 1291*acc8a4ebSJames Feist ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager", 1292*acc8a4ebSJames Feist path, pidConfigurationIface, "OutLimitMin", 1293*acc8a4ebSJames Feist static_cast<double>(offset)); 1294*acc8a4ebSJames Feist found = true; 1295*acc8a4ebSJames Feist } 1296*acc8a4ebSJames Feist } 1297*acc8a4ebSJames Feist if (!found) 1298*acc8a4ebSJames Feist { 1299*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1300*acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: set no fan offsets"); 1301*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1302*acc8a4ebSJames Feist } 1303*acc8a4ebSJames Feist 1304*acc8a4ebSJames Feist return ipmi::responseSuccess(); 1305*acc8a4ebSJames Feist } 1306*acc8a4ebSJames Feist 1307*acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1, 1308*acc8a4ebSJames Feist uint8_t param2) 13095f957cafSJames Feist { 13105f957cafSJames Feist constexpr const size_t disableLimiting = 0x0; 13115f957cafSJames Feist 1312*acc8a4ebSJames Feist if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 13135f957cafSJames Feist { 1314*acc8a4ebSJames Feist if (param1 == legacyExitAirSensorNumber) 1315faa4f223SJames Feist { 1316faa4f223SJames Feist std::string path = getExitAirConfigPath(); 1317faa4f223SJames Feist ipmi::setDbusProperty(dbus, "xyz.openbmc_project.EntityManager", 1318*acc8a4ebSJames Feist path, pidConfigurationIface, "SetPoint", 1319*acc8a4ebSJames Feist static_cast<double>(param2)); 1320*acc8a4ebSJames Feist return ipmi::responseSuccess(); 1321faa4f223SJames Feist } 1322faa4f223SJames Feist else 1323faa4f223SJames Feist { 1324*acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 1325faa4f223SJames Feist } 1326faa4f223SJames Feist } 1327*acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 13285f957cafSJames Feist { 1329*acc8a4ebSJames Feist uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8); 13305f957cafSJames Feist 13315f957cafSJames Feist // must be greater than 50 based on eps 13325f957cafSJames Feist if (cfm < 50 && cfm != disableLimiting) 13335f957cafSJames Feist { 1334*acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 13355f957cafSJames Feist } 13365f957cafSJames Feist 13375f957cafSJames Feist try 13385f957cafSJames Feist { 13395f957cafSJames Feist ipmi::setDbusProperty(dbus, settingsBusName, cfmLimitSettingPath, 13405f957cafSJames Feist cfmLimitIface, "Limit", 13415f957cafSJames Feist static_cast<double>(cfm)); 13425f957cafSJames Feist } 13435f957cafSJames Feist catch (sdbusplus::exception_t& e) 13445f957cafSJames Feist { 13455f957cafSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 13465f957cafSJames Feist "ipmiOEMSetFscParameter: can't set cfm setting!", 13475f957cafSJames Feist phosphor::logging::entry("ERR=%s", e.what())); 1348*acc8a4ebSJames Feist return ipmi::responseResponseError(); 13495f957cafSJames Feist } 1350*acc8a4ebSJames Feist return ipmi::responseSuccess(); 1351*acc8a4ebSJames Feist } 1352*acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1353*acc8a4ebSJames Feist { 1354*acc8a4ebSJames Feist constexpr const size_t maxDomainCount = 8; 1355*acc8a4ebSJames Feist uint8_t requestedDomainMask = param1; 1356*acc8a4ebSJames Feist boost::container::flat_map data = getPidConfigs(); 1357*acc8a4ebSJames Feist if (data.empty()) 1358*acc8a4ebSJames Feist { 1359*acc8a4ebSJames Feist 1360*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1361*acc8a4ebSJames Feist "ipmiOEMSetFscParameter: found no pid configurations!"); 1362*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1363*acc8a4ebSJames Feist } 1364*acc8a4ebSJames Feist size_t count = 0; 1365*acc8a4ebSJames Feist for (const auto& [path, pid] : data) 1366*acc8a4ebSJames Feist { 1367*acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1368*acc8a4ebSJames Feist if (findClass == pid.end()) 1369*acc8a4ebSJames Feist { 1370*acc8a4ebSJames Feist 1371*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1372*acc8a4ebSJames Feist "ipmiOEMSetFscParameter: found illegal pid " 1373*acc8a4ebSJames Feist "configurations"); 1374*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1375*acc8a4ebSJames Feist } 1376*acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1377*acc8a4ebSJames Feist if (type == "fan") 1378*acc8a4ebSJames Feist { 1379*acc8a4ebSJames Feist if (requestedDomainMask & (1 << count)) 1380*acc8a4ebSJames Feist { 1381*acc8a4ebSJames Feist ipmi::setDbusProperty( 1382*acc8a4ebSJames Feist dbus, "xyz.openbmc_project.EntityManager", path, 1383*acc8a4ebSJames Feist pidConfigurationIface, "OutLimitMax", 1384*acc8a4ebSJames Feist static_cast<double>(param2)); 1385*acc8a4ebSJames Feist } 1386*acc8a4ebSJames Feist count++; 1387*acc8a4ebSJames Feist } 1388*acc8a4ebSJames Feist } 1389*acc8a4ebSJames Feist return ipmi::responseSuccess(); 13905f957cafSJames Feist } 13915f957cafSJames Feist else 13925f957cafSJames Feist { 13935f957cafSJames Feist // todo other command parts possibly 13945f957cafSJames Feist // tcontrol is handled in peci now 13955f957cafSJames Feist // fan speed offset not implemented yet 13965f957cafSJames Feist // domain pwm limit not implemented 1397*acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 13985f957cafSJames Feist } 13995f957cafSJames Feist } 14005f957cafSJames Feist 1401*acc8a4ebSJames Feist ipmi::RspType< 1402*acc8a4ebSJames Feist std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>> 1403*acc8a4ebSJames Feist ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param) 14045f957cafSJames Feist { 1405faa4f223SJames Feist constexpr uint8_t legacyDefaultExitAirLimit = -128; 14065f957cafSJames Feist 1407*acc8a4ebSJames Feist if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 14085f957cafSJames Feist { 1409*acc8a4ebSJames Feist if (!param) 1410*acc8a4ebSJames Feist { 1411*acc8a4ebSJames Feist return ipmi::responseReqDataLenInvalid(); 14125f957cafSJames Feist } 14135f957cafSJames Feist 1414*acc8a4ebSJames Feist if (*param != legacyExitAirSensorNumber) 1415faa4f223SJames Feist { 1416*acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 1417faa4f223SJames Feist } 1418faa4f223SJames Feist uint8_t setpoint = legacyDefaultExitAirLimit; 1419faa4f223SJames Feist std::string path = getExitAirConfigPath(); 1420faa4f223SJames Feist if (path.size()) 1421faa4f223SJames Feist { 1422*acc8a4ebSJames Feist Value val = 1423*acc8a4ebSJames Feist ipmi::getDbusProperty(dbus, "xyz.openbmc_project.EntityManager", 1424*acc8a4ebSJames Feist path, pidConfigurationIface, "SetPoint"); 1425faa4f223SJames Feist setpoint = std::floor(std::get<double>(val) + 0.5); 1426faa4f223SJames Feist } 1427faa4f223SJames Feist 1428faa4f223SJames Feist // old implementation used to return the "default" and current, we 1429faa4f223SJames Feist // don't make the default readily available so just make both the 1430faa4f223SJames Feist // same 1431faa4f223SJames Feist 1432*acc8a4ebSJames Feist return ipmi::responseSuccess( 1433*acc8a4ebSJames Feist std::array<uint8_t, 2>{setpoint, setpoint}); 1434faa4f223SJames Feist } 1435*acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1436*acc8a4ebSJames Feist { 1437*acc8a4ebSJames Feist constexpr const size_t maxDomainCount = 8; 1438*acc8a4ebSJames Feist 1439*acc8a4ebSJames Feist if (!param) 1440*acc8a4ebSJames Feist { 1441*acc8a4ebSJames Feist return ipmi::responseReqDataLenInvalid(); 1442*acc8a4ebSJames Feist } 1443*acc8a4ebSJames Feist uint8_t requestedDomain = *param; 1444*acc8a4ebSJames Feist if (requestedDomain >= maxDomainCount) 1445*acc8a4ebSJames Feist { 1446*acc8a4ebSJames Feist return ipmi::responseInvalidFieldRequest(); 1447*acc8a4ebSJames Feist } 1448*acc8a4ebSJames Feist 1449*acc8a4ebSJames Feist boost::container::flat_map data = getPidConfigs(); 1450*acc8a4ebSJames Feist if (data.empty()) 1451*acc8a4ebSJames Feist { 1452*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1453*acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found no pid configurations!"); 1454*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1455*acc8a4ebSJames Feist } 1456*acc8a4ebSJames Feist size_t count = 0; 1457*acc8a4ebSJames Feist for (const auto& [_, pid] : data) 1458*acc8a4ebSJames Feist { 1459*acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1460*acc8a4ebSJames Feist if (findClass == pid.end()) 1461*acc8a4ebSJames Feist { 1462*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1463*acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 1464*acc8a4ebSJames Feist "configurations"); 1465*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1466*acc8a4ebSJames Feist } 1467*acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1468*acc8a4ebSJames Feist if (type == "fan") 1469*acc8a4ebSJames Feist { 1470*acc8a4ebSJames Feist if (requestedDomain == count) 1471*acc8a4ebSJames Feist { 1472*acc8a4ebSJames Feist auto findOutLimit = pid.find("OutLimitMax"); 1473*acc8a4ebSJames Feist if (findOutLimit == pid.end()) 1474*acc8a4ebSJames Feist { 1475*acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1476*acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 1477*acc8a4ebSJames Feist "configurations"); 1478*acc8a4ebSJames Feist return ipmi::responseResponseError(); 1479*acc8a4ebSJames Feist } 1480*acc8a4ebSJames Feist 1481*acc8a4ebSJames Feist return ipmi::responseSuccess( 1482*acc8a4ebSJames Feist static_cast<uint8_t>(std::floor( 1483*acc8a4ebSJames Feist std::get<double>(findOutLimit->second) + 0.5))); 1484*acc8a4ebSJames Feist } 1485*acc8a4ebSJames Feist else 1486*acc8a4ebSJames Feist { 1487*acc8a4ebSJames Feist count++; 1488*acc8a4ebSJames Feist } 1489*acc8a4ebSJames Feist } 1490*acc8a4ebSJames Feist } 1491*acc8a4ebSJames Feist 1492*acc8a4ebSJames Feist return ipmi::responseInvalidFieldRequest(); 1493*acc8a4ebSJames Feist } 1494*acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 14955f957cafSJames Feist { 14965f957cafSJames Feist 14975f957cafSJames Feist /* 14985f957cafSJames Feist DataLen should be 1, but host is sending us an extra bit. As the 1499*acc8a4ebSJames Feist previous behavior didn't seem to prevent this, ignore the check for 1500*acc8a4ebSJames Feist now. 15015f957cafSJames Feist 1502*acc8a4ebSJames Feist if (param) 15035f957cafSJames Feist { 15045f957cafSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 15055f957cafSJames Feist "ipmiOEMGetFscParameter: invalid input len!"); 15065f957cafSJames Feist return IPMI_CC_REQ_DATA_LEN_INVALID; 15075f957cafSJames Feist } 15085f957cafSJames Feist */ 15095f957cafSJames Feist Value cfmLimit; 15105f957cafSJames Feist Value cfmMaximum; 15115f957cafSJames Feist try 15125f957cafSJames Feist { 15135f957cafSJames Feist cfmLimit = ipmi::getDbusProperty(dbus, settingsBusName, 15145f957cafSJames Feist cfmLimitSettingPath, cfmLimitIface, 15155f957cafSJames Feist "Limit"); 15165f957cafSJames Feist cfmMaximum = ipmi::getDbusProperty( 15175f957cafSJames Feist dbus, "xyz.openbmc_project.ExitAirTempSensor", 15185f957cafSJames Feist "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit"); 15195f957cafSJames Feist } 15205f957cafSJames Feist catch (sdbusplus::exception_t& e) 15215f957cafSJames Feist { 15225f957cafSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1523*acc8a4ebSJames Feist "ipmiOEMGetFscParameter: can't get cfm setting!", 15245f957cafSJames Feist phosphor::logging::entry("ERR=%s", e.what())); 1525*acc8a4ebSJames Feist return ipmi::responseResponseError(); 15265f957cafSJames Feist } 15275f957cafSJames Feist 1528*acc8a4ebSJames Feist double cfmMax = std::get<double>(cfmMaximum); 1529*acc8a4ebSJames Feist double cfmLim = std::get<double>(cfmLimit); 1530*acc8a4ebSJames Feist 1531*acc8a4ebSJames Feist cfmLim = std::floor(cfmLim + 0.5); 1532*acc8a4ebSJames Feist cfmMax = std::floor(cfmMax + 0.5); 1533*acc8a4ebSJames Feist uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim); 1534*acc8a4ebSJames Feist uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax); 1535*acc8a4ebSJames Feist 1536*acc8a4ebSJames Feist return ipmi::responseSuccess( 1537*acc8a4ebSJames Feist std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp}); 15385f957cafSJames Feist } 15395f957cafSJames Feist 15405f957cafSJames Feist else 15415f957cafSJames Feist { 15425f957cafSJames Feist // todo other command parts possibly 15435f957cafSJames Feist // domain pwm limit not implemented 1544*acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 15455f957cafSJames Feist } 15465f957cafSJames Feist } 15475f957cafSJames Feist 154864796041SJason M. Bills static void registerOEMFunctions(void) 1549a835eaa0SJia, Chunhui { 1550a835eaa0SJia, Chunhui phosphor::logging::log<phosphor::logging::level::INFO>( 1551a835eaa0SJia, Chunhui "Registering OEM commands"); 155264796041SJason M. Bills ipmiPrintAndRegister(netfnIntcOEMGeneral, IPMI_CMD_WILDCARD, NULL, 1553a835eaa0SJia, Chunhui ipmiOEMWildcard, 1554a835eaa0SJia, Chunhui PRIVILEGE_USER); // wildcard default handler 155564796041SJason M. Bills ipmiPrintAndRegister(netfunIntelAppOEM, IPMI_CMD_WILDCARD, NULL, 155664796041SJason M. Bills ipmiOEMWildcard, 155764796041SJason M. Bills PRIVILEGE_USER); // wildcard default handler 155864796041SJason M. Bills ipmiPrintAndRegister( 155964796041SJason M. Bills netfnIntcOEMGeneral, 156064796041SJason M. Bills static_cast<ipmi_cmd_t>( 156164796041SJason M. Bills IPMINetfnIntelOEMGeneralCmd::cmdGetChassisIdentifier), 156264796041SJason M. Bills NULL, ipmiOEMGetChassisIdentifier, 1563a835eaa0SJia, Chunhui PRIVILEGE_USER); // get chassis identifier 156464796041SJason M. Bills ipmiPrintAndRegister( 156564796041SJason M. Bills netfnIntcOEMGeneral, 156664796041SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetSystemGUID), 156764796041SJason M. Bills NULL, ipmiOEMSetSystemGUID, 1568a835eaa0SJia, Chunhui PRIVILEGE_ADMIN); // set system guid 156964796041SJason M. Bills ipmiPrintAndRegister( 157064796041SJason M. Bills netfnIntcOEMGeneral, 157164796041SJason M. Bills static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetBIOSID), 157264796041SJason M. Bills NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN); 157364796041SJason M. Bills ipmiPrintAndRegister(netfnIntcOEMGeneral, 157464796041SJason M. Bills static_cast<ipmi_cmd_t>( 157564796041SJason M. Bills IPMINetfnIntelOEMGeneralCmd::cmdGetOEMDeviceInfo), 157664796041SJason M. Bills NULL, ipmiOEMGetDeviceInfo, PRIVILEGE_USER); 157764796041SJason M. Bills ipmiPrintAndRegister( 157864796041SJason M. Bills netfnIntcOEMGeneral, 157964796041SJason M. Bills static_cast<ipmi_cmd_t>( 158064796041SJason M. Bills IPMINetfnIntelOEMGeneralCmd::cmdGetAICSlotFRUIDSlotPosRecords), 158164796041SJason M. Bills NULL, ipmiOEMGetAICFRU, PRIVILEGE_USER); 1582cc49b54bSJia, Chunhui 1583cc49b54bSJia, Chunhui ipmi::registerHandler( 1584cc49b54bSJia, Chunhui ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 1585cc49b54bSJia, Chunhui static_cast<ipmi::Cmd>( 1586cc49b54bSJia, Chunhui IPMINetfnIntelOEMGeneralCmd::cmdSendEmbeddedFWUpdStatus), 1587cc49b54bSJia, Chunhui ipmi::Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus); 1588cc49b54bSJia, Chunhui 158964796041SJason M. Bills ipmiPrintAndRegister( 159064796041SJason M. Bills netfnIntcOEMGeneral, 159164796041SJason M. Bills static_cast<ipmi_cmd_t>( 159264796041SJason M. Bills IPMINetfnIntelOEMGeneralCmd::cmdSetPowerRestoreDelay), 159364796041SJason M. Bills NULL, ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR); 159464796041SJason M. Bills ipmiPrintAndRegister( 159564796041SJason M. Bills netfnIntcOEMGeneral, 159664796041SJason M. Bills static_cast<ipmi_cmd_t>( 159764796041SJason M. Bills IPMINetfnIntelOEMGeneralCmd::cmdGetPowerRestoreDelay), 159864796041SJason M. Bills NULL, ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER); 1599d509eb91SSuryakanth Sekar 1600d509eb91SSuryakanth Sekar ipmi::registerHandler( 1601d509eb91SSuryakanth Sekar ipmi::prioOpenBmcBase, ipmi::netFnOemOne, 1602d509eb91SSuryakanth Sekar static_cast<ipmi::Cmd>( 1603d509eb91SSuryakanth Sekar IPMINetfnIntelOEMGeneralCmd::cmdSetOEMUser2Activation), 1604d509eb91SSuryakanth Sekar ipmi::Privilege::Callback, ipmiOEMSetUser2Activation); 1605d509eb91SSuryakanth Sekar 160664796041SJason M. Bills ipmiPrintAndRegister( 160764796041SJason M. Bills netfnIntcOEMGeneral, 160864796041SJason M. Bills static_cast<ipmi_cmd_t>( 160964796041SJason M. Bills IPMINetfnIntelOEMGeneralCmd::cmdGetProcessorErrConfig), 161064796041SJason M. Bills NULL, ipmiOEMGetProcessorErrConfig, PRIVILEGE_USER); 161164796041SJason M. Bills ipmiPrintAndRegister( 161264796041SJason M. Bills netfnIntcOEMGeneral, 161364796041SJason M. Bills static_cast<ipmi_cmd_t>( 161464796041SJason M. Bills IPMINetfnIntelOEMGeneralCmd::cmdSetProcessorErrConfig), 161564796041SJason M. Bills NULL, ipmiOEMSetProcessorErrConfig, PRIVILEGE_ADMIN); 1616703922d0SYong Li ipmiPrintAndRegister(netfnIntcOEMGeneral, 1617703922d0SYong Li static_cast<ipmi_cmd_t>( 1618703922d0SYong Li IPMINetfnIntelOEMGeneralCmd::cmdSetShutdownPolicy), 1619703922d0SYong Li NULL, ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN); 1620703922d0SYong Li ipmiPrintAndRegister(netfnIntcOEMGeneral, 1621703922d0SYong Li static_cast<ipmi_cmd_t>( 1622703922d0SYong Li IPMINetfnIntelOEMGeneralCmd::cmdGetShutdownPolicy), 1623703922d0SYong Li NULL, ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN); 162491244a6aSJames Feist 162591244a6aSJames Feist ipmiPrintAndRegister( 162691244a6aSJames Feist netfnIntcOEMGeneral, 162791244a6aSJames Feist static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdSetFanConfig), 162891244a6aSJames Feist NULL, ipmiOEMSetFanConfig, PRIVILEGE_USER); 162991244a6aSJames Feist 163091244a6aSJames Feist ipmiPrintAndRegister( 163191244a6aSJames Feist netfnIntcOEMGeneral, 163291244a6aSJames Feist static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetFanConfig), 163391244a6aSJames Feist NULL, ipmiOEMGetFanConfig, PRIVILEGE_USER); 163491244a6aSJames Feist 1635*acc8a4ebSJames Feist ipmi::registerHandler( 1636*acc8a4ebSJames Feist ipmi::prioOemBase, netfnIntcOEMGeneral, 1637*acc8a4ebSJames Feist static_cast<ipmi::Cmd>( 1638*acc8a4ebSJames Feist IPMINetfnIntelOEMGeneralCmd::cmdGetFanSpeedOffset), 1639*acc8a4ebSJames Feist ipmi::Privilege::User, ipmiOEMGetFanSpeedOffset); 16405f957cafSJames Feist 1641*acc8a4ebSJames Feist ipmi::registerHandler( 1642*acc8a4ebSJames Feist ipmi::prioOemBase, netfnIntcOEMGeneral, 1643*acc8a4ebSJames Feist static_cast<ipmi::Cmd>( 1644*acc8a4ebSJames Feist IPMINetfnIntelOEMGeneralCmd::cmdSetFanSpeedOffset), 1645*acc8a4ebSJames Feist ipmi::Privilege::User, ipmiOEMSetFanSpeedOffset); 1646*acc8a4ebSJames Feist 1647*acc8a4ebSJames Feist ipmi::registerHandler( 1648*acc8a4ebSJames Feist ipmi::prioOemBase, netfnIntcOEMGeneral, 1649*acc8a4ebSJames Feist static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetFscParameter), 1650*acc8a4ebSJames Feist ipmi::Privilege::User, ipmiOEMSetFscParameter); 1651*acc8a4ebSJames Feist 1652*acc8a4ebSJames Feist ipmi::registerHandler( 1653*acc8a4ebSJames Feist ipmi::prioOemBase, netfnIntcOEMGeneral, 1654*acc8a4ebSJames Feist static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetFscParameter), 1655*acc8a4ebSJames Feist ipmi::Privilege::User, ipmiOEMGetFscParameter); 16565f957cafSJames Feist 165745f04988SKuiying Wang ipmiPrintAndRegister( 165845f04988SKuiying Wang netfnIntcOEMGeneral, 165945f04988SKuiying Wang static_cast<ipmi_cmd_t>(IPMINetfnIntelOEMGeneralCmd::cmdGetLEDStatus), 166045f04988SKuiying Wang NULL, ipmiOEMGetLEDStatus, PRIVILEGE_ADMIN); 166123737fe3SYong Li ipmiPrintAndRegister( 166223737fe3SYong Li netfnIntcOEMPlatform, 166323737fe3SYong Li static_cast<ipmi_cmd_t>( 166423737fe3SYong Li IPMINetfnIntelOEMPlatformCmd::cmdCfgHostSerialPortSpeed), 166523737fe3SYong Li NULL, ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN); 1666a835eaa0SJia, Chunhui return; 1667a835eaa0SJia, Chunhui } 1668a835eaa0SJia, Chunhui 1669a835eaa0SJia, Chunhui } // namespace ipmi 1670