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 17c2a07d4bSPatrick Venture #include "types.hpp" 1864796041SJason M. Bills #include "xyz/openbmc_project/Common/error.hpp" 1945f04988SKuiying Wang #include "xyz/openbmc_project/Led/Physical/server.hpp" 2064796041SJason M. Bills 219420416aSJayaprakash Mutyala #include <openssl/crypto.h> 22cc49b54bSJia, Chunhui #include <systemd/sd-journal.h> 23a835eaa0SJia, Chunhui 247a04f3a4SChen Yugang #include <appcommands.hpp> 2591244a6aSJames Feist #include <boost/container/flat_map.hpp> 2623737fe3SYong Li #include <boost/process/child.hpp> 2723737fe3SYong Li #include <boost/process/io.hpp> 280669d193SYong Li #include <com/intel/Control/OCOTShutdownPolicy/server.hpp> 2964796041SJason M. Bills #include <commandutils.hpp> 30ce4e73fdSZhikui Ren #include <gpiod.hpp> 31cc49b54bSJia, Chunhui #include <ipmid/api.hpp> 325480ef62SVernon Mauery #include <ipmid/utils.hpp> 3363efafacSJames Feist #include <nlohmann/json.hpp> 34a835eaa0SJia, Chunhui #include <oemcommands.hpp> 35a835eaa0SJia, Chunhui #include <phosphor-logging/log.hpp> 36a835eaa0SJia, Chunhui #include <sdbusplus/bus.hpp> 37d509eb91SSuryakanth Sekar #include <sdbusplus/message/types.hpp> 3897cf96e6SChen Yugang #include <xyz/openbmc_project/Chassis/Control/NMISource/server.hpp> 394f7e76bbSChen,Yugang #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> 404f7e76bbSChen,Yugang #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> 41773703a5SCheng C Yang #include <xyz/openbmc_project/Control/PowerSupplyRedundancy/server.hpp> 42d801e463SRichard Marian Thomaiyar #include <xyz/openbmc_project/Control/Security/RestrictionMode/server.hpp> 438d4f8d73SRichard Marian Thomaiyar #include <xyz/openbmc_project/Control/Security/SpecialMode/server.hpp> 44a835eaa0SJia, Chunhui 45fcd2d3a9SJames Feist #include <array> 46fcd2d3a9SJames Feist #include <filesystem> 47fcd2d3a9SJames Feist #include <iostream> 48fcd2d3a9SJames Feist #include <regex> 49fcd2d3a9SJames Feist #include <string> 50fcd2d3a9SJames Feist #include <variant> 51fcd2d3a9SJames Feist #include <vector> 52fcd2d3a9SJames Feist 53a835eaa0SJia, Chunhui namespace ipmi 54a835eaa0SJia, Chunhui { 5564796041SJason M. Bills static void registerOEMFunctions() __attribute__((constructor)); 564ac799d7SVernon Mauery 5764796041SJason M. Bills static constexpr size_t maxFRUStringLength = 0x3F; 58a835eaa0SJia, Chunhui 59d509eb91SSuryakanth Sekar static constexpr auto ethernetIntf = 60d509eb91SSuryakanth Sekar "xyz.openbmc_project.Network.EthernetInterface"; 61d509eb91SSuryakanth Sekar static constexpr auto networkIPIntf = "xyz.openbmc_project.Network.IP"; 62d509eb91SSuryakanth Sekar static constexpr auto networkService = "xyz.openbmc_project.Network"; 63d509eb91SSuryakanth Sekar static constexpr auto networkRoot = "/xyz/openbmc_project/network"; 64d509eb91SSuryakanth Sekar 6597cf96e6SChen Yugang static constexpr const char* oemNmiSourceIntf = 6697cf96e6SChen Yugang "xyz.openbmc_project.Chassis.Control.NMISource"; 6739736d59SChen Yugang static constexpr const char* oemNmiSourceObjPath = 6897cf96e6SChen Yugang "/xyz/openbmc_project/Chassis/Control/NMISource"; 6939736d59SChen Yugang static constexpr const char* oemNmiBmcSourceObjPathProp = "BMCSource"; 7039736d59SChen Yugang static constexpr const char* oemNmiEnabledObjPathProp = "Enabled"; 7139736d59SChen Yugang 7263efafacSJames Feist static constexpr const char* dimmOffsetFile = "/var/lib/ipmi/ipmi_dimms.json"; 732030d7c8Ssrikanta mondal static constexpr const char* multiNodeObjPath = 742030d7c8Ssrikanta mondal "/xyz/openbmc_project/MultiNode/Status"; 752030d7c8Ssrikanta mondal static constexpr const char* multiNodeIntf = 762030d7c8Ssrikanta mondal "xyz.openbmc_project.Chassis.MultiNode"; 7763efafacSJames Feist 7839736d59SChen Yugang enum class NmiSource : uint8_t 7939736d59SChen Yugang { 8039736d59SChen Yugang none = 0, 8197cf96e6SChen Yugang frontPanelButton = 1, 8297cf96e6SChen Yugang watchdog = 2, 8397cf96e6SChen Yugang chassisCmd = 3, 8497cf96e6SChen Yugang memoryError = 4, 8597cf96e6SChen Yugang pciBusError = 5, 8697cf96e6SChen Yugang pch = 6, 8797cf96e6SChen Yugang chipset = 7, 8839736d59SChen Yugang }; 8939736d59SChen Yugang 90822b0b40SSuryakanth Sekar enum class SpecialUserIndex : uint8_t 91822b0b40SSuryakanth Sekar { 92822b0b40SSuryakanth Sekar rootUser = 0, 93822b0b40SSuryakanth Sekar atScaleDebugUser = 1 94822b0b40SSuryakanth Sekar }; 95822b0b40SSuryakanth Sekar 96d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeService = 97d801e463SRichard Marian Thomaiyar "xyz.openbmc_project.RestrictionMode.Manager"; 98d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeBasePath = 99d801e463SRichard Marian Thomaiyar "/xyz/openbmc_project/control/security/restriction_mode"; 100d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeIntf = 101d801e463SRichard Marian Thomaiyar "xyz.openbmc_project.Control.Security.RestrictionMode"; 102d801e463SRichard Marian Thomaiyar static constexpr const char* restricionModeProperty = "RestrictionMode"; 103d801e463SRichard Marian Thomaiyar 104d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeService = 105d801e463SRichard Marian Thomaiyar "xyz.openbmc_project.SpecialMode"; 106d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeBasePath = 107a7b74288SRichard Marian Thomaiyar "/xyz/openbmc_project/security/special_mode"; 108d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeIntf = 109d801e463SRichard Marian Thomaiyar "xyz.openbmc_project.Security.SpecialMode"; 110d801e463SRichard Marian Thomaiyar static constexpr const char* specialModeProperty = "SpecialMode"; 111d801e463SRichard Marian Thomaiyar 112d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertyIntf = 113d801e463SRichard Marian Thomaiyar "org.freedesktop.DBus.Properties"; 114d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertyGetMethod = "Get"; 115d801e463SRichard Marian Thomaiyar static constexpr const char* dBusPropertySetMethod = "Set"; 116d801e463SRichard Marian Thomaiyar 117a835eaa0SJia, Chunhui // return code: 0 successful 118a835eaa0SJia, Chunhui int8_t getChassisSerialNumber(sdbusplus::bus::bus& bus, std::string& serial) 119a835eaa0SJia, Chunhui { 120a835eaa0SJia, Chunhui std::string objpath = "/xyz/openbmc_project/FruDevice"; 121a835eaa0SJia, Chunhui std::string intf = "xyz.openbmc_project.FruDeviceManager"; 122a835eaa0SJia, Chunhui std::string service = getService(bus, intf, objpath); 123a835eaa0SJia, Chunhui ObjectValueTree valueTree = getManagedObjects(bus, service, "/"); 124a835eaa0SJia, Chunhui if (valueTree.empty()) 125a835eaa0SJia, Chunhui { 126a835eaa0SJia, Chunhui phosphor::logging::log<phosphor::logging::level::ERR>( 127a835eaa0SJia, Chunhui "No object implements interface", 128a835eaa0SJia, Chunhui phosphor::logging::entry("INTF=%s", intf.c_str())); 129a835eaa0SJia, Chunhui return -1; 130a835eaa0SJia, Chunhui } 131a835eaa0SJia, Chunhui 13264796041SJason M. Bills for (const auto& item : valueTree) 133a835eaa0SJia, Chunhui { 134a835eaa0SJia, Chunhui auto interface = item.second.find("xyz.openbmc_project.FruDevice"); 135a835eaa0SJia, Chunhui if (interface == item.second.end()) 136a835eaa0SJia, Chunhui { 137a835eaa0SJia, Chunhui continue; 138a835eaa0SJia, Chunhui } 139a835eaa0SJia, Chunhui 140a835eaa0SJia, Chunhui auto property = interface->second.find("CHASSIS_SERIAL_NUMBER"); 141a835eaa0SJia, Chunhui if (property == interface->second.end()) 142a835eaa0SJia, Chunhui { 143a835eaa0SJia, Chunhui continue; 144a835eaa0SJia, Chunhui } 145a835eaa0SJia, Chunhui 146a835eaa0SJia, Chunhui try 147a835eaa0SJia, Chunhui { 148a835eaa0SJia, Chunhui Value variant = property->second; 1498166c8d7SVernon Mauery std::string& result = std::get<std::string>(variant); 15064796041SJason M. Bills if (result.size() > maxFRUStringLength) 151a835eaa0SJia, Chunhui { 152a835eaa0SJia, Chunhui phosphor::logging::log<phosphor::logging::level::ERR>( 153a835eaa0SJia, Chunhui "FRU serial number exceed maximum length"); 154a835eaa0SJia, Chunhui return -1; 155a835eaa0SJia, Chunhui } 156a835eaa0SJia, Chunhui serial = result; 157a835eaa0SJia, Chunhui return 0; 158a835eaa0SJia, Chunhui } 1598166c8d7SVernon Mauery catch (std::bad_variant_access& e) 160a835eaa0SJia, Chunhui { 16164796041SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 162a835eaa0SJia, Chunhui return -1; 163a835eaa0SJia, Chunhui } 164a835eaa0SJia, Chunhui } 165a835eaa0SJia, Chunhui return -1; 166a835eaa0SJia, Chunhui } 16764796041SJason M. Bills 168a835eaa0SJia, Chunhui // Returns the Chassis Identifier (serial #) 169a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetChassisIdentifier(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 170a835eaa0SJia, Chunhui ipmi_request_t request, 171a835eaa0SJia, Chunhui ipmi_response_t response, 17264796041SJason M. Bills ipmi_data_len_t dataLen, 173a835eaa0SJia, Chunhui ipmi_context_t context) 174a835eaa0SJia, Chunhui { 175a835eaa0SJia, Chunhui std::string serial; 17664796041SJason M. Bills if (*dataLen != 0) // invalid request if there are extra parameters 177a835eaa0SJia, Chunhui { 17864796041SJason M. Bills *dataLen = 0; 179a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 180a835eaa0SJia, Chunhui } 18115419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 18215419dd5SVernon Mauery if (getChassisSerialNumber(*dbus, serial) == 0) 183a835eaa0SJia, Chunhui { 18464796041SJason M. Bills *dataLen = serial.size(); // length will never exceed response length 185a835eaa0SJia, Chunhui // as it is checked in getChassisSerialNumber 186a835eaa0SJia, Chunhui char* resp = static_cast<char*>(response); 18764796041SJason M. Bills serial.copy(resp, *dataLen); 188a835eaa0SJia, Chunhui return IPMI_CC_OK; 189a835eaa0SJia, Chunhui } 19064796041SJason M. Bills *dataLen = 0; 191a835eaa0SJia, Chunhui return IPMI_CC_RESPONSE_ERROR; 192a835eaa0SJia, Chunhui } 193a835eaa0SJia, Chunhui 194a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetSystemGUID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 195a835eaa0SJia, Chunhui ipmi_request_t request, 196a835eaa0SJia, Chunhui ipmi_response_t response, 19764796041SJason M. Bills ipmi_data_len_t dataLen, ipmi_context_t context) 198a835eaa0SJia, Chunhui { 199a835eaa0SJia, Chunhui static constexpr size_t safeBufferLength = 50; 200a835eaa0SJia, Chunhui char buf[safeBufferLength] = {0}; 201a835eaa0SJia, Chunhui GUIDData* Data = reinterpret_cast<GUIDData*>(request); 202a835eaa0SJia, Chunhui 20364796041SJason M. Bills if (*dataLen != sizeof(GUIDData)) // 16bytes 204a835eaa0SJia, Chunhui { 20564796041SJason M. Bills *dataLen = 0; 206a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 207a835eaa0SJia, Chunhui } 208a835eaa0SJia, Chunhui 20964796041SJason M. Bills *dataLen = 0; 210a835eaa0SJia, Chunhui 211a835eaa0SJia, Chunhui snprintf( 212a835eaa0SJia, Chunhui buf, safeBufferLength, 213a835eaa0SJia, Chunhui "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", 214a835eaa0SJia, Chunhui Data->timeLow4, Data->timeLow3, Data->timeLow2, Data->timeLow1, 215a835eaa0SJia, Chunhui Data->timeMid2, Data->timeMid1, Data->timeHigh2, Data->timeHigh1, 216a835eaa0SJia, Chunhui Data->clock2, Data->clock1, Data->node6, Data->node5, Data->node4, 217a835eaa0SJia, Chunhui Data->node3, Data->node2, Data->node1); 218a835eaa0SJia, Chunhui // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 219a835eaa0SJia, Chunhui std::string guid = buf; 220a835eaa0SJia, Chunhui 221a835eaa0SJia, Chunhui std::string objpath = "/xyz/openbmc_project/control/host0/systemGUID"; 222a835eaa0SJia, Chunhui std::string intf = "xyz.openbmc_project.Common.UUID"; 22315419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 22415419dd5SVernon Mauery std::string service = getService(*dbus, intf, objpath); 22515419dd5SVernon Mauery setDbusProperty(*dbus, service, objpath, intf, "UUID", guid); 226a835eaa0SJia, Chunhui return IPMI_CC_OK; 227a835eaa0SJia, Chunhui } 228a835eaa0SJia, Chunhui 229b02bf095SJason M. Bills ipmi::RspType<> ipmiOEMDisableBMCSystemReset(bool disableResetOnSMI, 230b02bf095SJason M. Bills uint7_t reserved1) 231b02bf095SJason M. Bills { 232b02bf095SJason M. Bills std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 233b02bf095SJason M. Bills 234b02bf095SJason M. Bills try 235b02bf095SJason M. Bills { 236b02bf095SJason M. Bills auto service = 237b02bf095SJason M. Bills ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath); 238b02bf095SJason M. Bills ipmi::setDbusProperty(*busp, service, bmcResetDisablesPath, 239b02bf095SJason M. Bills bmcResetDisablesIntf, "ResetOnSMI", 240b02bf095SJason M. Bills !disableResetOnSMI); 241b02bf095SJason M. Bills } 242b02bf095SJason M. Bills catch (std::exception& e) 243b02bf095SJason M. Bills { 244b02bf095SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 245b02bf095SJason M. Bills "Failed to set BMC reset disables", 246b02bf095SJason M. Bills phosphor::logging::entry("EXCEPTION=%s", e.what())); 247b02bf095SJason M. Bills return ipmi::responseUnspecifiedError(); 248b02bf095SJason M. Bills } 249b02bf095SJason M. Bills 250b02bf095SJason M. Bills return ipmi::responseSuccess(); 251b02bf095SJason M. Bills } 252b02bf095SJason M. Bills 253b02bf095SJason M. Bills ipmi::RspType<bool, // disableResetOnSMI 254b02bf095SJason M. Bills uint7_t // reserved 255b02bf095SJason M. Bills > 256b02bf095SJason M. Bills ipmiOEMGetBMCResetDisables() 257b02bf095SJason M. Bills { 258b02bf095SJason M. Bills bool disableResetOnSMI = true; 259b02bf095SJason M. Bills 260b02bf095SJason M. Bills std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 261b02bf095SJason M. Bills try 262b02bf095SJason M. Bills { 263b02bf095SJason M. Bills auto service = 264b02bf095SJason M. Bills ipmi::getService(*busp, bmcResetDisablesIntf, bmcResetDisablesPath); 265b02bf095SJason M. Bills Value variant = 266b02bf095SJason M. Bills ipmi::getDbusProperty(*busp, service, bmcResetDisablesPath, 267b02bf095SJason M. Bills bmcResetDisablesIntf, "ResetOnSMI"); 268b02bf095SJason M. Bills disableResetOnSMI = !std::get<bool>(variant); 269b02bf095SJason M. Bills } 270b02bf095SJason M. Bills catch (std::exception& e) 271b02bf095SJason M. Bills { 272b02bf095SJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 273b02bf095SJason M. Bills "Failed to get BMC reset disables", 274b02bf095SJason M. Bills phosphor::logging::entry("EXCEPTION=%s", e.what())); 275b02bf095SJason M. Bills return ipmi::responseUnspecifiedError(); 276b02bf095SJason M. Bills } 277b02bf095SJason M. Bills 278b02bf095SJason M. Bills return ipmi::responseSuccess(disableResetOnSMI, 0); 279b02bf095SJason M. Bills } 280b02bf095SJason M. Bills 281a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMSetBIOSID(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 282a835eaa0SJia, Chunhui ipmi_request_t request, ipmi_response_t response, 283a835eaa0SJia, Chunhui ipmi_data_len_t dataLen, ipmi_context_t context) 284a835eaa0SJia, Chunhui { 285a835eaa0SJia, Chunhui DeviceInfo* data = reinterpret_cast<DeviceInfo*>(request); 286a835eaa0SJia, Chunhui 28764796041SJason M. Bills if ((*dataLen < 2) || (*dataLen != (1 + data->biosIDLength))) 288a835eaa0SJia, Chunhui { 289a835eaa0SJia, Chunhui *dataLen = 0; 290a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 291a835eaa0SJia, Chunhui } 29264796041SJason M. Bills std::string idString((char*)data->biosId, data->biosIDLength); 293*fb9f1aa1SChalapathi Venkataramashetty for (auto idChar : idString) 294*fb9f1aa1SChalapathi Venkataramashetty { 295*fb9f1aa1SChalapathi Venkataramashetty if (!std::isprint(static_cast<unsigned char>(idChar))) 296*fb9f1aa1SChalapathi Venkataramashetty { 297*fb9f1aa1SChalapathi Venkataramashetty phosphor::logging::log<phosphor::logging::level::ERR>( 298*fb9f1aa1SChalapathi Venkataramashetty "BIOS ID contains non printable character"); 299*fb9f1aa1SChalapathi Venkataramashetty return IPMI_CC_INVALID_FIELD_REQUEST; 300*fb9f1aa1SChalapathi Venkataramashetty } 301*fb9f1aa1SChalapathi Venkataramashetty } 302a835eaa0SJia, Chunhui 30315419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 304899bfd15SChalapathi std::string service = getService(*dbus, biosVersionIntf, biosActiveObjPath); 305899bfd15SChalapathi setDbusProperty(*dbus, service, biosActiveObjPath, biosVersionIntf, 3062742b85cSYong Li biosVersionProp, idString); 307a835eaa0SJia, Chunhui uint8_t* bytesWritten = static_cast<uint8_t*>(response); 308a835eaa0SJia, Chunhui *bytesWritten = 30964796041SJason M. Bills data->biosIDLength; // how many bytes are written into storage 310a835eaa0SJia, Chunhui *dataLen = 1; 311a835eaa0SJia, Chunhui return IPMI_CC_OK; 312a835eaa0SJia, Chunhui } 313a835eaa0SJia, Chunhui 314e99e7ed3SAppaRao Puli bool getSwVerInfo(ipmi::Context::ptr ctx, uint8_t& bmcMajor, uint8_t& bmcMinor, 315e99e7ed3SAppaRao Puli uint8_t& meMajor, uint8_t& meMinor) 316a835eaa0SJia, Chunhui { 3177a04f3a4SChen Yugang // step 1 : get BMC Major and Minor numbers from its DBUS property 318e99e7ed3SAppaRao Puli std::string bmcVersion; 319e99e7ed3SAppaRao Puli if (getActiveSoftwareVersionInfo(ctx, versionPurposeBMC, bmcVersion)) 3207a04f3a4SChen Yugang { 3217a04f3a4SChen Yugang return false; 322a835eaa0SJia, Chunhui } 323a835eaa0SJia, Chunhui 324e99e7ed3SAppaRao Puli std::optional<MetaRevision> rev = convertIntelVersion(bmcVersion); 3257a04f3a4SChen Yugang if (rev.has_value()) 326a835eaa0SJia, Chunhui { 3277a04f3a4SChen Yugang MetaRevision revision = rev.value(); 3287a04f3a4SChen Yugang bmcMajor = revision.major; 3297a04f3a4SChen Yugang 3307a04f3a4SChen Yugang revision.minor = (revision.minor > 99 ? 99 : revision.minor); 3317a04f3a4SChen Yugang bmcMinor = revision.minor % 10 + (revision.minor / 10) * 16; 3327a04f3a4SChen Yugang } 3337a04f3a4SChen Yugang 3347a04f3a4SChen Yugang // step 2 : get ME Major and Minor numbers from its DBUS property 33532825a23SAppaRao Puli std::string meVersion; 33632825a23SAppaRao Puli if (getActiveSoftwareVersionInfo(ctx, versionPurposeME, meVersion)) 3377a04f3a4SChen Yugang { 33832825a23SAppaRao Puli return false; 33932825a23SAppaRao Puli } 3407a04f3a4SChen Yugang std::regex pattern1("(\\d+?).(\\d+?).(\\d+?).(\\d+?).(\\d+?)"); 3417a04f3a4SChen Yugang constexpr size_t matchedPhosphor = 6; 3427a04f3a4SChen Yugang std::smatch results; 343d46cb42bSAppaRao Puli if (std::regex_match(meVersion, results, pattern1)) 3447a04f3a4SChen Yugang { 3457a04f3a4SChen Yugang if (results.size() == matchedPhosphor) 3467a04f3a4SChen Yugang { 3477a04f3a4SChen Yugang meMajor = static_cast<uint8_t>(std::stoi(results[1])); 3487a04f3a4SChen Yugang meMinor = static_cast<uint8_t>(std::stoi(results[2])); 3497a04f3a4SChen Yugang } 3507a04f3a4SChen Yugang } 3517a04f3a4SChen Yugang return true; 3527a04f3a4SChen Yugang } 3537a04f3a4SChen Yugang 3547a04f3a4SChen Yugang ipmi::RspType< 3557a04f3a4SChen Yugang std::variant<std::string, 3567a04f3a4SChen Yugang std::tuple<uint8_t, std::array<uint8_t, 2>, 3577a04f3a4SChen Yugang std::array<uint8_t, 2>, std::array<uint8_t, 2>, 3587a04f3a4SChen Yugang std::array<uint8_t, 2>, std::array<uint8_t, 2>>, 3597a04f3a4SChen Yugang std::tuple<uint8_t, std::array<uint8_t, 2>>>> 360e99e7ed3SAppaRao Puli ipmiOEMGetDeviceInfo(ipmi::Context::ptr ctx, uint8_t entityType, 361e99e7ed3SAppaRao Puli std::optional<uint8_t> countToRead, 362d46cb42bSAppaRao Puli std::optional<uint8_t> offset) 3637a04f3a4SChen Yugang { 3647a04f3a4SChen Yugang if (entityType > static_cast<uint8_t>(OEMDevEntityType::sdrVer)) 3657a04f3a4SChen Yugang { 3667a04f3a4SChen Yugang return ipmi::responseInvalidFieldRequest(); 367a835eaa0SJia, Chunhui } 368a835eaa0SJia, Chunhui 369a835eaa0SJia, Chunhui // handle OEM command items 3707a04f3a4SChen Yugang switch (OEMDevEntityType(entityType)) 371a835eaa0SJia, Chunhui { 372a835eaa0SJia, Chunhui case OEMDevEntityType::biosId: 373a835eaa0SJia, Chunhui { 374d46cb42bSAppaRao Puli // Byte 2&3, Only used with selecting BIOS 375d46cb42bSAppaRao Puli if (!countToRead || !offset) 376d46cb42bSAppaRao Puli { 377d46cb42bSAppaRao Puli return ipmi::responseReqDataLenInvalid(); 378d46cb42bSAppaRao Puli } 379d46cb42bSAppaRao Puli 38015419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 3812742b85cSYong Li std::string service = 382899bfd15SChalapathi getService(*dbus, biosVersionIntf, biosActiveObjPath); 383a835eaa0SJia, Chunhui try 384a835eaa0SJia, Chunhui { 3852742b85cSYong Li Value variant = 386899bfd15SChalapathi getDbusProperty(*dbus, service, biosActiveObjPath, 3872742b85cSYong Li biosVersionIntf, biosVersionProp); 3888166c8d7SVernon Mauery std::string& idString = std::get<std::string>(variant); 389d46cb42bSAppaRao Puli if (*offset >= idString.size()) 390a835eaa0SJia, Chunhui { 3917a04f3a4SChen Yugang return ipmi::responseParmOutOfRange(); 392a835eaa0SJia, Chunhui } 393a835eaa0SJia, Chunhui size_t length = 0; 394d46cb42bSAppaRao Puli if (*countToRead > (idString.size() - *offset)) 395a835eaa0SJia, Chunhui { 396d46cb42bSAppaRao Puli length = idString.size() - *offset; 397a835eaa0SJia, Chunhui } 398a835eaa0SJia, Chunhui else 399a835eaa0SJia, Chunhui { 400d46cb42bSAppaRao Puli length = *countToRead; 401a835eaa0SJia, Chunhui } 4027a04f3a4SChen Yugang 4037a04f3a4SChen Yugang std::string readBuf = {0}; 4047a04f3a4SChen Yugang readBuf.resize(length); 405d46cb42bSAppaRao Puli std::copy_n(idString.begin() + *offset, length, 4067a04f3a4SChen Yugang (readBuf.begin())); 4077a04f3a4SChen Yugang return ipmi::responseSuccess(readBuf); 408a835eaa0SJia, Chunhui } 4098166c8d7SVernon Mauery catch (std::bad_variant_access& e) 410a835eaa0SJia, Chunhui { 4117a04f3a4SChen Yugang return ipmi::responseUnspecifiedError(); 412a835eaa0SJia, Chunhui } 413a835eaa0SJia, Chunhui } 414a835eaa0SJia, Chunhui break; 415a835eaa0SJia, Chunhui 416a835eaa0SJia, Chunhui case OEMDevEntityType::devVer: 4177a04f3a4SChen Yugang { 418d46cb42bSAppaRao Puli // Byte 2&3, Only used with selecting BIOS 419d46cb42bSAppaRao Puli if (countToRead || offset) 420d46cb42bSAppaRao Puli { 421d46cb42bSAppaRao Puli return ipmi::responseReqDataLenInvalid(); 422d46cb42bSAppaRao Puli } 423d46cb42bSAppaRao Puli 4247a04f3a4SChen Yugang constexpr const size_t verLen = 2; 4257a04f3a4SChen Yugang constexpr const size_t verTotalLen = 10; 4267a04f3a4SChen Yugang std::array<uint8_t, verLen> bmcBuf = {0xff, 0xff}; 4277a04f3a4SChen Yugang std::array<uint8_t, verLen> hsc0Buf = {0xff, 0xff}; 4287a04f3a4SChen Yugang std::array<uint8_t, verLen> hsc1Buf = {0xff, 0xff}; 4297a04f3a4SChen Yugang std::array<uint8_t, verLen> meBuf = {0xff, 0xff}; 4307a04f3a4SChen Yugang std::array<uint8_t, verLen> hsc2Buf = {0xff, 0xff}; 4317a04f3a4SChen Yugang // data0/1: BMC version number; data6/7: ME version number 4327a04f3a4SChen Yugang // the others: HSC0/1/2 version number, not avaible. 433e99e7ed3SAppaRao Puli if (!getSwVerInfo(ctx, bmcBuf[0], bmcBuf[1], meBuf[0], meBuf[1])) 4347a04f3a4SChen Yugang { 4357a04f3a4SChen Yugang return ipmi::responseUnspecifiedError(); 436a835eaa0SJia, Chunhui } 4377a04f3a4SChen Yugang return ipmi::responseSuccess( 4387a04f3a4SChen Yugang std::tuple< 4397a04f3a4SChen Yugang uint8_t, std::array<uint8_t, verLen>, 4407a04f3a4SChen Yugang std::array<uint8_t, verLen>, std::array<uint8_t, verLen>, 4417a04f3a4SChen Yugang std::array<uint8_t, verLen>, std::array<uint8_t, verLen>>{ 4427a04f3a4SChen Yugang verTotalLen, bmcBuf, hsc0Buf, hsc1Buf, meBuf, hsc2Buf}); 4437a04f3a4SChen Yugang } 4447a04f3a4SChen Yugang break; 4457a04f3a4SChen Yugang 4467a04f3a4SChen Yugang case OEMDevEntityType::sdrVer: 4477a04f3a4SChen Yugang { 448d46cb42bSAppaRao Puli // Byte 2&3, Only used with selecting BIOS 449d46cb42bSAppaRao Puli if (countToRead || offset) 450d46cb42bSAppaRao Puli { 451d46cb42bSAppaRao Puli return ipmi::responseReqDataLenInvalid(); 452d46cb42bSAppaRao Puli } 453d46cb42bSAppaRao Puli 4547a04f3a4SChen Yugang constexpr const size_t sdrLen = 2; 4557a04f3a4SChen Yugang std::array<uint8_t, sdrLen> readBuf = {0x01, 0x0}; 4567a04f3a4SChen Yugang return ipmi::responseSuccess( 4577a04f3a4SChen Yugang std::tuple<uint8_t, std::array<uint8_t, sdrLen>>{sdrLen, 4587a04f3a4SChen Yugang readBuf}); 4597a04f3a4SChen Yugang } 4607a04f3a4SChen Yugang break; 4617a04f3a4SChen Yugang 4627a04f3a4SChen Yugang default: 4637a04f3a4SChen Yugang return ipmi::responseInvalidFieldRequest(); 4647a04f3a4SChen Yugang } 465a835eaa0SJia, Chunhui } 466a835eaa0SJia, Chunhui 467a835eaa0SJia, Chunhui ipmi_ret_t ipmiOEMGetAICFRU(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 468a835eaa0SJia, Chunhui ipmi_request_t request, ipmi_response_t response, 469a835eaa0SJia, Chunhui ipmi_data_len_t dataLen, ipmi_context_t context) 470a835eaa0SJia, Chunhui { 471a835eaa0SJia, Chunhui if (*dataLen != 0) 472a835eaa0SJia, Chunhui { 47364796041SJason M. Bills *dataLen = 0; 474a835eaa0SJia, Chunhui return IPMI_CC_REQ_DATA_LEN_INVALID; 475a835eaa0SJia, Chunhui } 476a835eaa0SJia, Chunhui 477a835eaa0SJia, Chunhui *dataLen = 1; 478a835eaa0SJia, Chunhui uint8_t* res = reinterpret_cast<uint8_t*>(response); 479a835eaa0SJia, Chunhui // temporary fix. We don't support AIC FRU now. Just tell BIOS that no 480a835eaa0SJia, Chunhui // AIC is available so that BIOS will not timeout repeatly which leads to 481a835eaa0SJia, Chunhui // slow booting. 482a835eaa0SJia, Chunhui *res = 0; // Byte1=Count of SlotPosition/FruID records. 483a835eaa0SJia, Chunhui return IPMI_CC_OK; 484a835eaa0SJia, Chunhui } 485a835eaa0SJia, Chunhui 48664796041SJason M. Bills ipmi_ret_t ipmiOEMGetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 48764796041SJason M. Bills ipmi_request_t request, 48864796041SJason M. Bills ipmi_response_t response, 48964796041SJason M. Bills ipmi_data_len_t dataLen, 49064796041SJason M. Bills ipmi_context_t context) 491a835eaa0SJia, Chunhui { 49264796041SJason M. Bills GetPowerRestoreDelayRes* resp = 49364796041SJason M. Bills reinterpret_cast<GetPowerRestoreDelayRes*>(response); 49464796041SJason M. Bills 49564796041SJason M. Bills if (*dataLen != 0) 49664796041SJason M. Bills { 49764796041SJason M. Bills *dataLen = 0; 49864796041SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 499a835eaa0SJia, Chunhui } 500a835eaa0SJia, Chunhui 50115419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 50264796041SJason M. Bills std::string service = 50315419dd5SVernon Mauery getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 50464796041SJason M. Bills Value variant = 50515419dd5SVernon Mauery getDbusProperty(*dbus, service, powerRestoreDelayObjPath, 50664796041SJason M. Bills powerRestoreDelayIntf, powerRestoreDelayProp); 50764796041SJason M. Bills 5088166c8d7SVernon Mauery uint16_t delay = std::get<uint16_t>(variant); 50964796041SJason M. Bills resp->byteLSB = delay; 51064796041SJason M. Bills resp->byteMSB = delay >> 8; 51164796041SJason M. Bills 51264796041SJason M. Bills *dataLen = sizeof(GetPowerRestoreDelayRes); 51364796041SJason M. Bills 51464796041SJason M. Bills return IPMI_CC_OK; 51564796041SJason M. Bills } 51664796041SJason M. Bills 517cc49b54bSJia, Chunhui static uint8_t bcdToDec(uint8_t val) 518cc49b54bSJia, Chunhui { 519cc49b54bSJia, Chunhui return ((val / 16 * 10) + (val % 16)); 520cc49b54bSJia, Chunhui } 521cc49b54bSJia, Chunhui 522cc49b54bSJia, Chunhui // Allows an update utility or system BIOS to send the status of an embedded 523cc49b54bSJia, Chunhui // firmware update attempt to the BMC. After received, BMC will create a logging 524cc49b54bSJia, Chunhui // record. 525cc49b54bSJia, Chunhui ipmi::RspType<> ipmiOEMSendEmbeddedFwUpdStatus(uint8_t status, uint8_t target, 526cc49b54bSJia, Chunhui uint8_t majorRevision, 527cc49b54bSJia, Chunhui uint8_t minorRevision, 528cc49b54bSJia, Chunhui uint32_t auxInfo) 529cc49b54bSJia, Chunhui { 530cc49b54bSJia, Chunhui std::string firmware; 531dc24927fSJason M. Bills int instance = (target & targetInstanceMask) >> targetInstanceShift; 532cc49b54bSJia, Chunhui target = (target & selEvtTargetMask) >> selEvtTargetShift; 533cc49b54bSJia, Chunhui 534cc49b54bSJia, Chunhui /* make sure the status is 0, 1, or 2 as per the spec */ 535cc49b54bSJia, Chunhui if (status > 2) 536cc49b54bSJia, Chunhui { 537cc49b54bSJia, Chunhui return ipmi::response(ipmi::ccInvalidFieldRequest); 538cc49b54bSJia, Chunhui } 539dc24927fSJason M. Bills /* make sure the target is 0, 1, 2, or 4 as per the spec */ 540dc24927fSJason M. Bills if (target > 4 || target == 3) 541dc24927fSJason M. Bills { 542dc24927fSJason M. Bills return ipmi::response(ipmi::ccInvalidFieldRequest); 543dc24927fSJason M. Bills } 544cc49b54bSJia, Chunhui /*orignal OEM command is to record OEM SEL. 545cc49b54bSJia, Chunhui But openbmc does not support OEM SEL, so we redirect it to redfish event 546cc49b54bSJia, Chunhui logging. */ 547cc49b54bSJia, Chunhui std::string buildInfo; 548cc49b54bSJia, Chunhui std::string action; 549cc49b54bSJia, Chunhui switch (FWUpdateTarget(target)) 550cc49b54bSJia, Chunhui { 551cc49b54bSJia, Chunhui case FWUpdateTarget::targetBMC: 552cc49b54bSJia, Chunhui firmware = "BMC"; 553dc24927fSJason M. Bills buildInfo = "major: " + std::to_string(majorRevision) + " minor: " + 554cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 555cc49b54bSJia, Chunhui " BuildID: " + std::to_string(auxInfo); 556cc49b54bSJia, Chunhui buildInfo += std::to_string(auxInfo); 557cc49b54bSJia, Chunhui break; 558cc49b54bSJia, Chunhui case FWUpdateTarget::targetBIOS: 559cc49b54bSJia, Chunhui firmware = "BIOS"; 560cc49b54bSJia, Chunhui buildInfo = 561cc49b54bSJia, Chunhui "major: " + 562cc49b54bSJia, Chunhui std::to_string(bcdToDec(majorRevision)) + // BCD encoded 563cc49b54bSJia, Chunhui " minor: " + 564cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 565cc49b54bSJia, Chunhui " ReleaseNumber: " + // ASCII encoded 566cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 0) - '0') + 567cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 8) - '0') + 568cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 16) - '0') + 569cc49b54bSJia, Chunhui std::to_string(static_cast<uint8_t>(auxInfo >> 24) - '0'); 570cc49b54bSJia, Chunhui break; 571cc49b54bSJia, Chunhui case FWUpdateTarget::targetME: 572cc49b54bSJia, Chunhui firmware = "ME"; 573cc49b54bSJia, Chunhui buildInfo = 574cc49b54bSJia, Chunhui "major: " + std::to_string(majorRevision) + " minor1: " + 575cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 576cc49b54bSJia, Chunhui " minor2: " + 577cc49b54bSJia, Chunhui std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 0))) + 578cc49b54bSJia, Chunhui " build1: " + 579cc49b54bSJia, Chunhui std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 8))) + 580cc49b54bSJia, Chunhui " build2: " + 581cc49b54bSJia, Chunhui std::to_string(bcdToDec(static_cast<uint8_t>(auxInfo >> 16))); 582cc49b54bSJia, Chunhui break; 583cc49b54bSJia, Chunhui case FWUpdateTarget::targetOEMEWS: 584cc49b54bSJia, Chunhui firmware = "EWS"; 585dc24927fSJason M. Bills buildInfo = "major: " + std::to_string(majorRevision) + " minor: " + 586cc49b54bSJia, Chunhui std::to_string(bcdToDec(minorRevision)) + // BCD encoded 587cc49b54bSJia, Chunhui " BuildID: " + std::to_string(auxInfo); 588cc49b54bSJia, Chunhui break; 589cc49b54bSJia, Chunhui } 590cc49b54bSJia, Chunhui 591dc24927fSJason M. Bills static const std::string openBMCMessageRegistryVersion("0.1"); 592dc24927fSJason M. Bills std::string redfishMsgID = "OpenBMC." + openBMCMessageRegistryVersion; 593dc24927fSJason M. Bills 594cc49b54bSJia, Chunhui switch (status) 595cc49b54bSJia, Chunhui { 596cc49b54bSJia, Chunhui case 0x0: 597cc49b54bSJia, Chunhui action = "update started"; 598dc24927fSJason M. Bills redfishMsgID += ".FirmwareUpdateStarted"; 599cc49b54bSJia, Chunhui break; 600cc49b54bSJia, Chunhui case 0x1: 601cc49b54bSJia, Chunhui action = "update completed successfully"; 602dc24927fSJason M. Bills redfishMsgID += ".FirmwareUpdateCompleted"; 603cc49b54bSJia, Chunhui break; 604cc49b54bSJia, Chunhui case 0x2: 605cc49b54bSJia, Chunhui action = "update failure"; 606dc24927fSJason M. Bills redfishMsgID += ".FirmwareUpdateFailed"; 607cc49b54bSJia, Chunhui break; 608cc49b54bSJia, Chunhui default: 609cc49b54bSJia, Chunhui action = "unknown"; 610cc49b54bSJia, Chunhui break; 611cc49b54bSJia, Chunhui } 612cc49b54bSJia, Chunhui 613dc24927fSJason M. Bills std::string firmwareInstanceStr = 614dc24927fSJason M. Bills firmware + " instance: " + std::to_string(instance); 615dc24927fSJason M. Bills std::string message("[firmware update] " + firmwareInstanceStr + 616cc49b54bSJia, Chunhui " status: <" + action + "> " + buildInfo); 617cc49b54bSJia, Chunhui 618cc49b54bSJia, Chunhui sd_journal_send("MESSAGE=%s", message.c_str(), "PRIORITY=%i", LOG_INFO, 619dc24927fSJason M. Bills "REDFISH_MESSAGE_ID=%s", redfishMsgID.c_str(), 620dc24927fSJason M. Bills "REDFISH_MESSAGE_ARGS=%s,%s", firmwareInstanceStr.c_str(), 621dc24927fSJason M. Bills buildInfo.c_str(), NULL); 622cc49b54bSJia, Chunhui return ipmi::responseSuccess(); 623cc49b54bSJia, Chunhui } 624cc49b54bSJia, Chunhui 6252b664d5aSRajashekar Gade Reddy ipmi::RspType<uint8_t, std::vector<uint8_t>> 6262b664d5aSRajashekar Gade Reddy ipmiOEMSlotIpmb(ipmi::Context::ptr ctx, uint6_t reserved1, 6272b664d5aSRajashekar Gade Reddy uint2_t slotNumber, uint3_t baseBoardSlotNum, 6282b664d5aSRajashekar Gade Reddy uint3_t riserSlotNum, uint2_t reserved2, uint8_t slaveAddr, 6292b664d5aSRajashekar Gade Reddy uint8_t netFn, uint8_t cmd, 6302b664d5aSRajashekar Gade Reddy std::optional<std::vector<uint8_t>> writeData) 6312b664d5aSRajashekar Gade Reddy { 6322b664d5aSRajashekar Gade Reddy if (reserved1 || reserved2) 6332b664d5aSRajashekar Gade Reddy { 6342b664d5aSRajashekar Gade Reddy return ipmi::responseInvalidFieldRequest(); 6352b664d5aSRajashekar Gade Reddy } 6362b664d5aSRajashekar Gade Reddy 6372b664d5aSRajashekar Gade Reddy boost::system::error_code ec; 6382b664d5aSRajashekar Gade Reddy using ipmbResponse = std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, 6392b664d5aSRajashekar Gade Reddy std::vector<uint8_t>>; 6402b664d5aSRajashekar Gade Reddy ipmbResponse res = ctx->bus->yield_method_call<ipmbResponse>( 6412b664d5aSRajashekar Gade Reddy ctx->yield, ec, "xyz.openbmc_project.Ipmi.Channel.Ipmb", 6422b664d5aSRajashekar Gade Reddy "/xyz/openbmc_project/Ipmi/Channel/Ipmb", "org.openbmc.Ipmb", 6432b664d5aSRajashekar Gade Reddy "SlotIpmbRequest", static_cast<uint8_t>(slotNumber), 6442b664d5aSRajashekar Gade Reddy static_cast<uint8_t>(baseBoardSlotNum), slaveAddr, netFn, cmd, 6452b664d5aSRajashekar Gade Reddy *writeData); 6462b664d5aSRajashekar Gade Reddy if (ec) 6472b664d5aSRajashekar Gade Reddy { 6482b664d5aSRajashekar Gade Reddy phosphor::logging::log<phosphor::logging::level::ERR>( 6492b664d5aSRajashekar Gade Reddy "Failed to call dbus method SlotIpmbRequest"); 6502b664d5aSRajashekar Gade Reddy return ipmi::responseUnspecifiedError(); 6512b664d5aSRajashekar Gade Reddy } 6522b664d5aSRajashekar Gade Reddy 6532b664d5aSRajashekar Gade Reddy std::vector<uint8_t> dataReceived(0); 6542b664d5aSRajashekar Gade Reddy int status = -1; 6552b664d5aSRajashekar Gade Reddy uint8_t resNetFn = 0, resLun = 0, resCmd = 0, cc = 0; 6562b664d5aSRajashekar Gade Reddy 6572b664d5aSRajashekar Gade Reddy std::tie(status, resNetFn, resLun, resCmd, cc, dataReceived) = res; 6582b664d5aSRajashekar Gade Reddy 6592b664d5aSRajashekar Gade Reddy if (status) 6602b664d5aSRajashekar Gade Reddy { 6612b664d5aSRajashekar Gade Reddy phosphor::logging::log<phosphor::logging::level::ERR>( 6622b664d5aSRajashekar Gade Reddy "Failed to get response from SlotIpmbRequest"); 6632b664d5aSRajashekar Gade Reddy return ipmi::responseResponseError(); 6642b664d5aSRajashekar Gade Reddy } 6652b664d5aSRajashekar Gade Reddy return ipmi::responseSuccess(cc, dataReceived); 6662b664d5aSRajashekar Gade Reddy } 6672b664d5aSRajashekar Gade Reddy 66864796041SJason M. Bills ipmi_ret_t ipmiOEMSetPowerRestoreDelay(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 66964796041SJason M. Bills ipmi_request_t request, 67064796041SJason M. Bills ipmi_response_t response, 67164796041SJason M. Bills ipmi_data_len_t dataLen, 67264796041SJason M. Bills ipmi_context_t context) 67364796041SJason M. Bills { 67464796041SJason M. Bills SetPowerRestoreDelayReq* data = 67564796041SJason M. Bills reinterpret_cast<SetPowerRestoreDelayReq*>(request); 67664796041SJason M. Bills uint16_t delay = 0; 67764796041SJason M. Bills 67864796041SJason M. Bills if (*dataLen != sizeof(SetPowerRestoreDelayReq)) 67964796041SJason M. Bills { 68064796041SJason M. Bills *dataLen = 0; 68164796041SJason M. Bills return IPMI_CC_REQ_DATA_LEN_INVALID; 68264796041SJason M. Bills } 68364796041SJason M. Bills delay = data->byteMSB; 68464796041SJason M. Bills delay = (delay << 8) | data->byteLSB; 68515419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 68664796041SJason M. Bills std::string service = 68715419dd5SVernon Mauery getService(*dbus, powerRestoreDelayIntf, powerRestoreDelayObjPath); 68815419dd5SVernon Mauery setDbusProperty(*dbus, service, powerRestoreDelayObjPath, 68964796041SJason M. Bills powerRestoreDelayIntf, powerRestoreDelayProp, delay); 69064796041SJason M. Bills *dataLen = 0; 69164796041SJason M. Bills 69264796041SJason M. Bills return IPMI_CC_OK; 69364796041SJason M. Bills } 69464796041SJason M. Bills 69542bd9c8eSJason M. Bills static bool cpuPresent(const std::string& cpuName) 69664796041SJason M. Bills { 69742bd9c8eSJason M. Bills static constexpr const char* cpuPresencePathPrefix = 69842bd9c8eSJason M. Bills "/xyz/openbmc_project/inventory/system/chassis/motherboard/"; 69942bd9c8eSJason M. Bills static constexpr const char* cpuPresenceIntf = 70042bd9c8eSJason M. Bills "xyz.openbmc_project.Inventory.Item"; 70142bd9c8eSJason M. Bills std::string cpuPresencePath = cpuPresencePathPrefix + cpuName; 70242bd9c8eSJason M. Bills std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 70342bd9c8eSJason M. Bills try 70442bd9c8eSJason M. Bills { 70542bd9c8eSJason M. Bills auto service = 70642bd9c8eSJason M. Bills ipmi::getService(*busp, cpuPresenceIntf, cpuPresencePath); 70764796041SJason M. Bills 70842bd9c8eSJason M. Bills ipmi::Value result = ipmi::getDbusProperty( 70942bd9c8eSJason M. Bills *busp, service, cpuPresencePath, cpuPresenceIntf, "Present"); 71042bd9c8eSJason M. Bills return std::get<bool>(result); 71142bd9c8eSJason M. Bills } 71242bd9c8eSJason M. Bills catch (const std::exception& e) 71364796041SJason M. Bills { 71442bd9c8eSJason M. Bills phosphor::logging::log<phosphor::logging::level::INFO>( 71542bd9c8eSJason M. Bills "Cannot find processor presence", 71642bd9c8eSJason M. Bills phosphor::logging::entry("NAME=%s", cpuName.c_str())); 71742bd9c8eSJason M. Bills return false; 71842bd9c8eSJason M. Bills } 71964796041SJason M. Bills } 72064796041SJason M. Bills 72142bd9c8eSJason M. Bills ipmi::RspType<bool, // CATERR Reset Enabled 72242bd9c8eSJason M. Bills bool, // ERR2 Reset Enabled 72342bd9c8eSJason M. Bills uint6_t, // reserved 72442bd9c8eSJason M. Bills uint8_t, // reserved, returns 0x3F 72542bd9c8eSJason M. Bills uint6_t, // CPU1 CATERR Count 72642bd9c8eSJason M. Bills uint2_t, // CPU1 Status 72742bd9c8eSJason M. Bills uint6_t, // CPU2 CATERR Count 72842bd9c8eSJason M. Bills uint2_t, // CPU2 Status 72942bd9c8eSJason M. Bills uint6_t, // CPU3 CATERR Count 73042bd9c8eSJason M. Bills uint2_t, // CPU3 Status 73142bd9c8eSJason M. Bills uint6_t, // CPU4 CATERR Count 73242bd9c8eSJason M. Bills uint2_t, // CPU4 Status 73342bd9c8eSJason M. Bills uint8_t // Crashdump Count 73442bd9c8eSJason M. Bills > 73542bd9c8eSJason M. Bills ipmiOEMGetProcessorErrConfig() 73642bd9c8eSJason M. Bills { 73742bd9c8eSJason M. Bills bool resetOnCATERR = false; 73842bd9c8eSJason M. Bills bool resetOnERR2 = false; 73942bd9c8eSJason M. Bills uint6_t cpu1CATERRCount = 0; 74042bd9c8eSJason M. Bills uint6_t cpu2CATERRCount = 0; 74142bd9c8eSJason M. Bills uint6_t cpu3CATERRCount = 0; 74242bd9c8eSJason M. Bills uint6_t cpu4CATERRCount = 0; 74342bd9c8eSJason M. Bills uint8_t crashdumpCount = 0; 74442bd9c8eSJason M. Bills uint2_t cpu1Status = 74542bd9c8eSJason M. Bills cpuPresent("CPU_1") ? CPUStatus::enabled : CPUStatus::notPresent; 74642bd9c8eSJason M. Bills uint2_t cpu2Status = 74742bd9c8eSJason M. Bills cpuPresent("CPU_2") ? CPUStatus::enabled : CPUStatus::notPresent; 74842bd9c8eSJason M. Bills uint2_t cpu3Status = 74942bd9c8eSJason M. Bills cpuPresent("CPU_3") ? CPUStatus::enabled : CPUStatus::notPresent; 75042bd9c8eSJason M. Bills uint2_t cpu4Status = 75142bd9c8eSJason M. Bills cpuPresent("CPU_4") ? CPUStatus::enabled : CPUStatus::notPresent; 75264796041SJason M. Bills 75342bd9c8eSJason M. Bills std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 75442bd9c8eSJason M. Bills try 75542bd9c8eSJason M. Bills { 75642bd9c8eSJason M. Bills auto service = ipmi::getService(*busp, processorErrConfigIntf, 75742bd9c8eSJason M. Bills processorErrConfigObjPath); 75864796041SJason M. Bills 75942bd9c8eSJason M. Bills ipmi::PropertyMap result = ipmi::getAllDbusProperties( 76042bd9c8eSJason M. Bills *busp, service, processorErrConfigObjPath, processorErrConfigIntf); 76142bd9c8eSJason M. Bills resetOnCATERR = std::get<bool>(result.at("ResetOnCATERR")); 76242bd9c8eSJason M. Bills resetOnERR2 = std::get<bool>(result.at("ResetOnERR2")); 76342bd9c8eSJason M. Bills cpu1CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU1")); 76442bd9c8eSJason M. Bills cpu2CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU2")); 76542bd9c8eSJason M. Bills cpu3CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU3")); 76642bd9c8eSJason M. Bills cpu4CATERRCount = std::get<uint8_t>(result.at("ErrorCountCPU4")); 76742bd9c8eSJason M. Bills crashdumpCount = std::get<uint8_t>(result.at("CrashdumpCount")); 76842bd9c8eSJason M. Bills } 76942bd9c8eSJason M. Bills catch (const std::exception& e) 77042bd9c8eSJason M. Bills { 77142bd9c8eSJason M. Bills phosphor::logging::log<phosphor::logging::level::ERR>( 77242bd9c8eSJason M. Bills "Failed to fetch processor error config", 77342bd9c8eSJason M. Bills phosphor::logging::entry("ERROR=%s", e.what())); 77442bd9c8eSJason M. Bills return ipmi::responseUnspecifiedError(); 77542bd9c8eSJason M. Bills } 77664796041SJason M. Bills 77742bd9c8eSJason M. Bills return ipmi::responseSuccess(resetOnCATERR, resetOnERR2, 0, 0x3F, 77842bd9c8eSJason M. Bills cpu1CATERRCount, cpu1Status, cpu2CATERRCount, 77942bd9c8eSJason M. Bills cpu2Status, cpu3CATERRCount, cpu3Status, 78042bd9c8eSJason M. Bills cpu4CATERRCount, cpu4Status, crashdumpCount); 78142bd9c8eSJason M. Bills } 78242bd9c8eSJason M. Bills 78342bd9c8eSJason M. Bills ipmi::RspType<> ipmiOEMSetProcessorErrConfig( 78442bd9c8eSJason M. Bills bool resetOnCATERR, bool resetOnERR2, uint6_t reserved1, uint8_t reserved2, 78542bd9c8eSJason M. Bills std::optional<bool> clearCPUErrorCount, 78642bd9c8eSJason M. Bills std::optional<bool> clearCrashdumpCount, std::optional<uint6_t> reserved3) 78742bd9c8eSJason M. Bills { 78842bd9c8eSJason M. Bills std::shared_ptr<sdbusplus::asio::connection> busp = getSdBus(); 78964796041SJason M. Bills 79064796041SJason M. Bills try 79164796041SJason M. Bills { 79242bd9c8eSJason M. Bills auto service = ipmi::getService(*busp, processorErrConfigIntf, 79342bd9c8eSJason M. Bills processorErrConfigObjPath); 79442bd9c8eSJason M. Bills ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 79542bd9c8eSJason M. Bills processorErrConfigIntf, "ResetOnCATERR", 79642bd9c8eSJason M. Bills resetOnCATERR); 79742bd9c8eSJason M. Bills ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 79842bd9c8eSJason M. Bills processorErrConfigIntf, "ResetOnERR2", 79942bd9c8eSJason M. Bills resetOnERR2); 80042bd9c8eSJason M. Bills if (clearCPUErrorCount.value_or(false)) 80142bd9c8eSJason M. Bills { 80242bd9c8eSJason M. Bills ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 803d3e19936SJason M. Bills processorErrConfigIntf, "ErrorCountCPU1", 804d3e19936SJason M. Bills static_cast<uint8_t>(0)); 80542bd9c8eSJason M. Bills ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 806d3e19936SJason M. Bills processorErrConfigIntf, "ErrorCountCPU2", 807d3e19936SJason M. Bills static_cast<uint8_t>(0)); 808d3e19936SJason M. Bills ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 809d3e19936SJason M. Bills processorErrConfigIntf, "ErrorCountCPU3", 810d3e19936SJason M. Bills static_cast<uint8_t>(0)); 811d3e19936SJason M. Bills ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 812d3e19936SJason M. Bills processorErrConfigIntf, "ErrorCountCPU4", 813d3e19936SJason M. Bills static_cast<uint8_t>(0)); 81464796041SJason M. Bills } 81542bd9c8eSJason M. Bills if (clearCrashdumpCount.value_or(false)) 81642bd9c8eSJason M. Bills { 81742bd9c8eSJason M. Bills ipmi::setDbusProperty(*busp, service, processorErrConfigObjPath, 818d3e19936SJason M. Bills processorErrConfigIntf, "CrashdumpCount", 819d3e19936SJason M. Bills static_cast<uint8_t>(0)); 82042bd9c8eSJason M. Bills } 82142bd9c8eSJason M. Bills } 82242bd9c8eSJason M. Bills catch (std::exception& e) 82364796041SJason M. Bills { 824bc546679SKuiying Wang phosphor::logging::log<phosphor::logging::level::ERR>( 82542bd9c8eSJason M. Bills "Failed to set processor error config", 82642bd9c8eSJason M. Bills phosphor::logging::entry("EXCEPTION=%s", e.what())); 82742bd9c8eSJason M. Bills return ipmi::responseUnspecifiedError(); 82864796041SJason M. Bills } 82964796041SJason M. Bills 83042bd9c8eSJason M. Bills return ipmi::responseSuccess(); 83164796041SJason M. Bills } 83264796041SJason M. Bills 833703922d0SYong Li ipmi_ret_t ipmiOEMGetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 834703922d0SYong Li ipmi_request_t request, 835703922d0SYong Li ipmi_response_t response, 836703922d0SYong Li ipmi_data_len_t dataLen, 837703922d0SYong Li ipmi_context_t context) 838703922d0SYong Li { 839703922d0SYong Li GetOEMShutdownPolicyRes* resp = 840703922d0SYong Li reinterpret_cast<GetOEMShutdownPolicyRes*>(response); 841703922d0SYong Li 842703922d0SYong Li if (*dataLen != 0) 843703922d0SYong Li { 844703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 84545f04988SKuiying Wang "oem_get_shutdown_policy: invalid input len!"); 846703922d0SYong Li *dataLen = 0; 847703922d0SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 848703922d0SYong Li } 849703922d0SYong Li 850703922d0SYong Li *dataLen = 0; 851703922d0SYong Li 852703922d0SYong Li try 853703922d0SYong Li { 85415419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 855703922d0SYong Li std::string service = 85615419dd5SVernon Mauery getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 85715419dd5SVernon Mauery Value variant = getDbusProperty( 85815419dd5SVernon Mauery *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf, 859703922d0SYong Li oemShutdownPolicyObjPathProp); 8600669d193SYong Li 8610669d193SYong Li if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 8620669d193SYong Li convertPolicyFromString(std::get<std::string>(variant)) == 8630669d193SYong Li sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy:: 8640669d193SYong Li NoShutdownOnOCOT) 8650669d193SYong Li { 8660669d193SYong Li resp->policy = 0; 8670669d193SYong Li } 8680669d193SYong Li else if (sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 8690669d193SYong Li convertPolicyFromString(std::get<std::string>(variant)) == 8700669d193SYong Li sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 8710669d193SYong Li Policy::ShutdownOnOCOT) 8720669d193SYong Li { 8730669d193SYong Li resp->policy = 1; 8740669d193SYong Li } 8750669d193SYong Li else 8760669d193SYong Li { 8770669d193SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 8780669d193SYong Li "oem_set_shutdown_policy: invalid property!", 8790669d193SYong Li phosphor::logging::entry( 8800669d193SYong Li "PROP=%s", std::get<std::string>(variant).c_str())); 8810669d193SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 8820669d193SYong Li } 883703922d0SYong Li // TODO needs to check if it is multi-node products, 884703922d0SYong Li // policy is only supported on node 3/4 885703922d0SYong Li resp->policySupport = shutdownPolicySupported; 886703922d0SYong Li } 887703922d0SYong Li catch (sdbusplus::exception_t& e) 888703922d0SYong Li { 889703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 890703922d0SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 891703922d0SYong Li } 892703922d0SYong Li 893703922d0SYong Li *dataLen = sizeof(GetOEMShutdownPolicyRes); 894703922d0SYong Li return IPMI_CC_OK; 895703922d0SYong Li } 896703922d0SYong Li 897703922d0SYong Li ipmi_ret_t ipmiOEMSetShutdownPolicy(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 898703922d0SYong Li ipmi_request_t request, 899703922d0SYong Li ipmi_response_t response, 900703922d0SYong Li ipmi_data_len_t dataLen, 901703922d0SYong Li ipmi_context_t context) 902703922d0SYong Li { 903703922d0SYong Li uint8_t* req = reinterpret_cast<uint8_t*>(request); 9040669d193SYong Li sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy policy = 9050669d193SYong Li sdbusplus::com::intel::Control::server::OCOTShutdownPolicy::Policy:: 9060669d193SYong Li NoShutdownOnOCOT; 907703922d0SYong Li 908703922d0SYong Li // TODO needs to check if it is multi-node products, 909703922d0SYong Li // policy is only supported on node 3/4 910703922d0SYong Li if (*dataLen != 1) 911703922d0SYong Li { 912703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 913703922d0SYong Li "oem_set_shutdown_policy: invalid input len!"); 914703922d0SYong Li *dataLen = 0; 915703922d0SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 916703922d0SYong Li } 917703922d0SYong Li 918703922d0SYong Li *dataLen = 0; 919703922d0SYong Li if ((*req != noShutdownOnOCOT) && (*req != shutdownOnOCOT)) 920703922d0SYong Li { 921703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 922703922d0SYong Li "oem_set_shutdown_policy: invalid input!"); 923703922d0SYong Li return IPMI_CC_INVALID_FIELD_REQUEST; 924703922d0SYong Li } 925703922d0SYong Li 9260669d193SYong Li if (*req == noShutdownOnOCOT) 9270669d193SYong Li { 9280669d193SYong Li policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 9290669d193SYong Li Policy::NoShutdownOnOCOT; 9300669d193SYong Li } 9310669d193SYong Li else 9320669d193SYong Li { 9330669d193SYong Li policy = sdbusplus::com::intel::Control::server::OCOTShutdownPolicy:: 9340669d193SYong Li Policy::ShutdownOnOCOT; 9350669d193SYong Li } 9360669d193SYong Li 937703922d0SYong Li try 938703922d0SYong Li { 93915419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 940703922d0SYong Li std::string service = 94115419dd5SVernon Mauery getService(*dbus, oemShutdownPolicyIntf, oemShutdownPolicyObjPath); 9420669d193SYong Li setDbusProperty( 94315419dd5SVernon Mauery *dbus, service, oemShutdownPolicyObjPath, oemShutdownPolicyIntf, 9440669d193SYong Li oemShutdownPolicyObjPathProp, 9450669d193SYong Li sdbusplus::com::intel::Control::server::convertForMessage(policy)); 946703922d0SYong Li } 947703922d0SYong Li catch (sdbusplus::exception_t& e) 948703922d0SYong Li { 949703922d0SYong Li phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 950703922d0SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 951703922d0SYong Li } 952703922d0SYong Li 953703922d0SYong Li return IPMI_CC_OK; 954703922d0SYong Li } 955703922d0SYong Li 956d509eb91SSuryakanth Sekar /** @brief implementation for check the DHCP or not in IPv4 957d509eb91SSuryakanth Sekar * @param[in] Channel - Channel number 958d509eb91SSuryakanth Sekar * @returns true or false. 959d509eb91SSuryakanth Sekar */ 960d509eb91SSuryakanth Sekar static bool isDHCPEnabled(uint8_t Channel) 961d509eb91SSuryakanth Sekar { 962d509eb91SSuryakanth Sekar try 963d509eb91SSuryakanth Sekar { 964d509eb91SSuryakanth Sekar auto ethdevice = getChannelName(Channel); 965d509eb91SSuryakanth Sekar if (ethdevice.empty()) 966d509eb91SSuryakanth Sekar { 967d509eb91SSuryakanth Sekar return false; 968d509eb91SSuryakanth Sekar } 969d509eb91SSuryakanth Sekar auto ethIP = ethdevice + "/ipv4"; 97015419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 971d509eb91SSuryakanth Sekar auto ethernetObj = 97215419dd5SVernon Mauery getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP); 97315419dd5SVernon Mauery auto value = getDbusProperty(*dbus, networkService, ethernetObj.first, 974d509eb91SSuryakanth Sekar networkIPIntf, "Origin"); 9758166c8d7SVernon Mauery if (std::get<std::string>(value) == 976d509eb91SSuryakanth Sekar "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 977d509eb91SSuryakanth Sekar { 978d509eb91SSuryakanth Sekar return true; 979d509eb91SSuryakanth Sekar } 980d509eb91SSuryakanth Sekar else 981d509eb91SSuryakanth Sekar { 982d509eb91SSuryakanth Sekar return false; 983d509eb91SSuryakanth Sekar } 984d509eb91SSuryakanth Sekar } 985d509eb91SSuryakanth Sekar catch (sdbusplus::exception_t& e) 986d509eb91SSuryakanth Sekar { 987d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 988d509eb91SSuryakanth Sekar return true; 989d509eb91SSuryakanth Sekar } 990d509eb91SSuryakanth Sekar } 991d509eb91SSuryakanth Sekar 992d509eb91SSuryakanth Sekar /** @brief implementes for check the DHCP or not in IPv6 993d509eb91SSuryakanth Sekar * @param[in] Channel - Channel number 994d509eb91SSuryakanth Sekar * @returns true or false. 995d509eb91SSuryakanth Sekar */ 996d509eb91SSuryakanth Sekar static bool isDHCPIPv6Enabled(uint8_t Channel) 997d509eb91SSuryakanth Sekar { 998d509eb91SSuryakanth Sekar 999d509eb91SSuryakanth Sekar try 1000d509eb91SSuryakanth Sekar { 1001d509eb91SSuryakanth Sekar auto ethdevice = getChannelName(Channel); 1002d509eb91SSuryakanth Sekar if (ethdevice.empty()) 1003d509eb91SSuryakanth Sekar { 1004d509eb91SSuryakanth Sekar return false; 1005d509eb91SSuryakanth Sekar } 1006d509eb91SSuryakanth Sekar auto ethIP = ethdevice + "/ipv6"; 100715419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1008d509eb91SSuryakanth Sekar auto objectInfo = 100915419dd5SVernon Mauery getDbusObject(*dbus, networkIPIntf, networkRoot, ethIP); 101015419dd5SVernon Mauery auto properties = getAllDbusProperties(*dbus, objectInfo.second, 1011d509eb91SSuryakanth Sekar objectInfo.first, networkIPIntf); 10128166c8d7SVernon Mauery if (std::get<std::string>(properties["Origin"]) == 1013d509eb91SSuryakanth Sekar "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP") 1014d509eb91SSuryakanth Sekar { 1015d509eb91SSuryakanth Sekar return true; 1016d509eb91SSuryakanth Sekar } 1017d509eb91SSuryakanth Sekar else 1018d509eb91SSuryakanth Sekar { 1019d509eb91SSuryakanth Sekar return false; 1020d509eb91SSuryakanth Sekar } 1021d509eb91SSuryakanth Sekar } 1022d509eb91SSuryakanth Sekar catch (sdbusplus::exception_t& e) 1023d509eb91SSuryakanth Sekar { 1024d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>(e.description()); 1025d509eb91SSuryakanth Sekar return true; 1026d509eb91SSuryakanth Sekar } 1027d509eb91SSuryakanth Sekar } 1028d509eb91SSuryakanth Sekar 1029d509eb91SSuryakanth Sekar /** @brief implementes the creating of default new user 1030d509eb91SSuryakanth Sekar * @param[in] userName - new username in 16 bytes. 1031d509eb91SSuryakanth Sekar * @param[in] userPassword - new password in 20 bytes 1032d509eb91SSuryakanth Sekar * @returns ipmi completion code. 1033d509eb91SSuryakanth Sekar */ 1034d509eb91SSuryakanth Sekar ipmi::RspType<> ipmiOEMSetUser2Activation( 1035d509eb91SSuryakanth Sekar std::array<uint8_t, ipmi::ipmiMaxUserName>& userName, 1036d509eb91SSuryakanth Sekar std::array<uint8_t, ipmi::maxIpmi20PasswordSize>& userPassword) 1037d509eb91SSuryakanth Sekar { 1038d509eb91SSuryakanth Sekar bool userState = false; 1039d509eb91SSuryakanth Sekar // Check for System Interface not exist and LAN should be static 1040d509eb91SSuryakanth Sekar for (uint8_t channel = 0; channel < maxIpmiChannels; channel++) 1041d509eb91SSuryakanth Sekar { 1042d509eb91SSuryakanth Sekar ChannelInfo chInfo; 1043d509eb91SSuryakanth Sekar try 1044d509eb91SSuryakanth Sekar { 1045d509eb91SSuryakanth Sekar getChannelInfo(channel, chInfo); 1046d509eb91SSuryakanth Sekar } 1047d509eb91SSuryakanth Sekar catch (sdbusplus::exception_t& e) 1048d509eb91SSuryakanth Sekar { 1049d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 1050d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: Failed to get Channel Info", 1051d509eb91SSuryakanth Sekar phosphor::logging::entry("MSG: %s", e.description())); 1052d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccUnspecifiedError); 1053d509eb91SSuryakanth Sekar } 1054d509eb91SSuryakanth Sekar if (chInfo.mediumType == 1055d509eb91SSuryakanth Sekar static_cast<uint8_t>(EChannelMediumType::systemInterface)) 1056d509eb91SSuryakanth Sekar { 1057d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 1058d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: system interface exist ."); 1059d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 1060d509eb91SSuryakanth Sekar } 1061d509eb91SSuryakanth Sekar else 1062d509eb91SSuryakanth Sekar { 1063d509eb91SSuryakanth Sekar 1064d509eb91SSuryakanth Sekar if (chInfo.mediumType == 1065d509eb91SSuryakanth Sekar static_cast<uint8_t>(EChannelMediumType::lan8032)) 1066d509eb91SSuryakanth Sekar { 1067d509eb91SSuryakanth Sekar if (isDHCPIPv6Enabled(channel) || isDHCPEnabled(channel)) 1068d509eb91SSuryakanth Sekar { 1069d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 1070d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: DHCP enabled ."); 1071d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 1072d509eb91SSuryakanth Sekar } 1073d509eb91SSuryakanth Sekar } 1074d509eb91SSuryakanth Sekar } 1075d509eb91SSuryakanth Sekar } 1076d509eb91SSuryakanth Sekar uint8_t maxChUsers = 0, enabledUsers = 0, fixedUsers = 0; 1077d509eb91SSuryakanth Sekar if (ipmi::ccSuccess == 1078d509eb91SSuryakanth Sekar ipmiUserGetAllCounts(maxChUsers, enabledUsers, fixedUsers)) 1079d509eb91SSuryakanth Sekar { 1080d509eb91SSuryakanth Sekar if (enabledUsers > 1) 1081d509eb91SSuryakanth Sekar { 1082d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 1083d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: more than one user is enabled."); 1084d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 1085d509eb91SSuryakanth Sekar } 1086d509eb91SSuryakanth Sekar // Check the user 2 is enabled or not 1087d509eb91SSuryakanth Sekar ipmiUserCheckEnabled(ipmiDefaultUserId, userState); 1088d509eb91SSuryakanth Sekar if (userState == true) 1089d509eb91SSuryakanth Sekar { 1090d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 1091d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: user 2 already enabled ."); 1092d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 1093d509eb91SSuryakanth Sekar } 1094d509eb91SSuryakanth Sekar } 1095d509eb91SSuryakanth Sekar else 1096d509eb91SSuryakanth Sekar { 1097d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccUnspecifiedError); 1098d509eb91SSuryakanth Sekar } 1099d509eb91SSuryakanth Sekar 1100d509eb91SSuryakanth Sekar #if BYTE_ORDER == LITTLE_ENDIAN 1101d509eb91SSuryakanth Sekar PrivAccess privAccess = {PRIVILEGE_ADMIN, true, true, true, 0}; 1102d509eb91SSuryakanth Sekar #endif 1103d509eb91SSuryakanth Sekar #if BYTE_ORDER == BIG_ENDIAN 1104d509eb91SSuryakanth Sekar PrivAccess privAccess = {0, true, true, true, PRIVILEGE_ADMIN}; 1105d509eb91SSuryakanth Sekar #endif 1106d509eb91SSuryakanth Sekar 1107037cabddSVernon Mauery // ipmiUserSetUserName correctly handles char*, possibly non-null 1108037cabddSVernon Mauery // terminated strings using ipmiMaxUserName size 11093fbe8d2aSJayaprakash Mutyala size_t nameLen = strnlen(reinterpret_cast<const char*>(userName.data()), 11103fbe8d2aSJayaprakash Mutyala sizeof(userName)); 11113fbe8d2aSJayaprakash Mutyala const std::string userNameRaw( 11123fbe8d2aSJayaprakash Mutyala reinterpret_cast<const char*>(userName.data()), nameLen); 11131429d4f1Sjayaprakash Mutyala 1114037cabddSVernon Mauery if (ipmi::ccSuccess == ipmiUserSetUserName(ipmiDefaultUserId, userNameRaw)) 1115d509eb91SSuryakanth Sekar { 1116d509eb91SSuryakanth Sekar if (ipmi::ccSuccess == 1117d509eb91SSuryakanth Sekar ipmiUserSetUserPassword( 1118d509eb91SSuryakanth Sekar ipmiDefaultUserId, 1119d509eb91SSuryakanth Sekar reinterpret_cast<const char*>(userPassword.data()))) 1120d509eb91SSuryakanth Sekar { 1121d509eb91SSuryakanth Sekar if (ipmi::ccSuccess == 1122d509eb91SSuryakanth Sekar ipmiUserSetPrivilegeAccess( 1123d509eb91SSuryakanth Sekar ipmiDefaultUserId, 1124d509eb91SSuryakanth Sekar static_cast<uint8_t>(ipmi::EChannelID::chanLan1), 1125d509eb91SSuryakanth Sekar privAccess, true)) 1126d509eb91SSuryakanth Sekar { 1127d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::INFO>( 1128d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: user created successfully "); 11299420416aSJayaprakash Mutyala OPENSSL_cleanse(userPassword.data(), userPassword.size()); 11309420416aSJayaprakash Mutyala 1131d509eb91SSuryakanth Sekar return ipmi::responseSuccess(); 1132d509eb91SSuryakanth Sekar } 1133d509eb91SSuryakanth Sekar } 1134d509eb91SSuryakanth Sekar // we need to delete the default user id which added in this command as 1135d509eb91SSuryakanth Sekar // password / priv setting is failed. 11363fbe8d2aSJayaprakash Mutyala ipmiUserSetUserName(ipmiDefaultUserId, static_cast<std::string>("")); 1137d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 1138d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: password / priv setting is failed."); 11399420416aSJayaprakash Mutyala OPENSSL_cleanse(userPassword.data(), userPassword.size()); 1140d509eb91SSuryakanth Sekar } 1141d509eb91SSuryakanth Sekar else 1142d509eb91SSuryakanth Sekar { 1143d509eb91SSuryakanth Sekar phosphor::logging::log<phosphor::logging::level::ERR>( 1144d509eb91SSuryakanth Sekar "ipmiOEMSetUser2Activation: Setting username failed."); 1145d509eb91SSuryakanth Sekar } 1146d509eb91SSuryakanth Sekar 1147d509eb91SSuryakanth Sekar return ipmi::response(ipmi::ccCommandNotAvailable); 1148d509eb91SSuryakanth Sekar } 1149d509eb91SSuryakanth Sekar 1150822b0b40SSuryakanth Sekar /** @brief implementes executing the linux command 1151822b0b40SSuryakanth Sekar * @param[in] linux command 1152822b0b40SSuryakanth Sekar * @returns status 1153822b0b40SSuryakanth Sekar */ 1154822b0b40SSuryakanth Sekar 1155822b0b40SSuryakanth Sekar static uint8_t executeCmd(const char* path) 1156822b0b40SSuryakanth Sekar { 1157822b0b40SSuryakanth Sekar boost::process::child execProg(path); 1158822b0b40SSuryakanth Sekar execProg.wait(); 1159822b0b40SSuryakanth Sekar 1160822b0b40SSuryakanth Sekar int retCode = execProg.exit_code(); 1161822b0b40SSuryakanth Sekar if (retCode) 1162822b0b40SSuryakanth Sekar { 1163822b0b40SSuryakanth Sekar return ipmi::ccUnspecifiedError; 1164822b0b40SSuryakanth Sekar } 1165822b0b40SSuryakanth Sekar return ipmi::ccSuccess; 1166822b0b40SSuryakanth Sekar } 1167822b0b40SSuryakanth Sekar 1168822b0b40SSuryakanth Sekar /** @brief implementes ASD Security event logging 1169822b0b40SSuryakanth Sekar * @param[in] Event message string 1170822b0b40SSuryakanth Sekar * @param[in] Event Severity 1171822b0b40SSuryakanth Sekar * @returns status 1172822b0b40SSuryakanth Sekar */ 1173822b0b40SSuryakanth Sekar 1174822b0b40SSuryakanth Sekar static void atScaleDebugEventlog(std::string msg, int severity) 1175822b0b40SSuryakanth Sekar { 1176822b0b40SSuryakanth Sekar std::string eventStr = "OpenBMC.0.1." + msg; 1177822b0b40SSuryakanth Sekar sd_journal_send("MESSAGE=Security Event: %s", eventStr.c_str(), 1178822b0b40SSuryakanth Sekar "PRIORITY=%i", severity, "REDFISH_MESSAGE_ID=%s", 1179822b0b40SSuryakanth Sekar eventStr.c_str(), NULL); 1180822b0b40SSuryakanth Sekar } 1181822b0b40SSuryakanth Sekar 1182fc5e985bSRichard Marian Thomaiyar /** @brief implementes setting password for special user 1183fc5e985bSRichard Marian Thomaiyar * @param[in] specialUserIndex 1184fc5e985bSRichard Marian Thomaiyar * @param[in] userPassword - new password in 20 bytes 1185fc5e985bSRichard Marian Thomaiyar * @returns ipmi completion code. 1186fc5e985bSRichard Marian Thomaiyar */ 1187fc5e985bSRichard Marian Thomaiyar ipmi::RspType<> ipmiOEMSetSpecialUserPassword(ipmi::Context::ptr ctx, 1188fc5e985bSRichard Marian Thomaiyar uint8_t specialUserIndex, 1189fc5e985bSRichard Marian Thomaiyar std::vector<uint8_t> userPassword) 1190fc5e985bSRichard Marian Thomaiyar { 1191fc5e985bSRichard Marian Thomaiyar ChannelInfo chInfo; 1192822b0b40SSuryakanth Sekar ipmi_ret_t status = ipmi::ccSuccess; 1193822b0b40SSuryakanth Sekar 1194fc5e985bSRichard Marian Thomaiyar try 1195fc5e985bSRichard Marian Thomaiyar { 1196fc5e985bSRichard Marian Thomaiyar getChannelInfo(ctx->channel, chInfo); 1197fc5e985bSRichard Marian Thomaiyar } 1198fc5e985bSRichard Marian Thomaiyar catch (sdbusplus::exception_t& e) 1199fc5e985bSRichard Marian Thomaiyar { 1200fc5e985bSRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 1201fc5e985bSRichard Marian Thomaiyar "ipmiOEMSetSpecialUserPassword: Failed to get Channel Info", 1202fc5e985bSRichard Marian Thomaiyar phosphor::logging::entry("MSG: %s", e.description())); 1203fc5e985bSRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 1204fc5e985bSRichard Marian Thomaiyar } 1205fc5e985bSRichard Marian Thomaiyar if (chInfo.mediumType != 1206fc5e985bSRichard Marian Thomaiyar static_cast<uint8_t>(EChannelMediumType::systemInterface)) 1207fc5e985bSRichard Marian Thomaiyar { 1208fc5e985bSRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 1209fc5e985bSRichard Marian Thomaiyar "ipmiOEMSetSpecialUserPassword: Error - supported only in KCS " 1210fc5e985bSRichard Marian Thomaiyar "interface"); 1211fc5e985bSRichard Marian Thomaiyar return ipmi::responseCommandNotAvailable(); 1212fc5e985bSRichard Marian Thomaiyar } 1213822b0b40SSuryakanth Sekar 1214822b0b40SSuryakanth Sekar // 0 for root user and 1 for AtScaleDebug is allowed 1215822b0b40SSuryakanth Sekar if (specialUserIndex > 1216822b0b40SSuryakanth Sekar static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser)) 1217fc5e985bSRichard Marian Thomaiyar { 1218fc5e985bSRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 1219fc5e985bSRichard Marian Thomaiyar "ipmiOEMSetSpecialUserPassword: Invalid user account"); 1220fc5e985bSRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 1221fc5e985bSRichard Marian Thomaiyar } 1222822b0b40SSuryakanth Sekar if (userPassword.size() != 0) 1223822b0b40SSuryakanth Sekar { 1224fc5e985bSRichard Marian Thomaiyar constexpr uint8_t minPasswordSizeRequired = 6; 1225822b0b40SSuryakanth Sekar std::string passwd; 1226fc5e985bSRichard Marian Thomaiyar if (userPassword.size() < minPasswordSizeRequired || 1227fc5e985bSRichard Marian Thomaiyar userPassword.size() > ipmi::maxIpmi20PasswordSize) 1228fc5e985bSRichard Marian Thomaiyar { 12299420416aSJayaprakash Mutyala OPENSSL_cleanse(userPassword.data(), userPassword.size()); 1230fc5e985bSRichard Marian Thomaiyar return ipmi::responseReqDataLenInvalid(); 1231fc5e985bSRichard Marian Thomaiyar } 1232fc5e985bSRichard Marian Thomaiyar passwd.assign(reinterpret_cast<const char*>(userPassword.data()), 1233fc5e985bSRichard Marian Thomaiyar userPassword.size()); 12349420416aSJayaprakash Mutyala // Clear sensitive data 12359420416aSJayaprakash Mutyala OPENSSL_cleanse(userPassword.data(), userPassword.size()); 1236822b0b40SSuryakanth Sekar if (specialUserIndex == 1237822b0b40SSuryakanth Sekar static_cast<uint8_t>(SpecialUserIndex::atScaleDebugUser)) 1238822b0b40SSuryakanth Sekar { 1239822b0b40SSuryakanth Sekar status = ipmiSetSpecialUserPassword("asdbg", passwd); 1240822b0b40SSuryakanth Sekar 1241822b0b40SSuryakanth Sekar atScaleDebugEventlog("AtScaleDebugSpecialUserEnabled", LOG_CRIT); 1242822b0b40SSuryakanth Sekar } 1243822b0b40SSuryakanth Sekar else 1244822b0b40SSuryakanth Sekar { 1245822b0b40SSuryakanth Sekar status = ipmiSetSpecialUserPassword("root", passwd); 1246822b0b40SSuryakanth Sekar } 12479420416aSJayaprakash Mutyala // Clear sensitive data 12489420416aSJayaprakash Mutyala OPENSSL_cleanse(&passwd, passwd.length()); 12499420416aSJayaprakash Mutyala 1250822b0b40SSuryakanth Sekar return ipmi::response(status); 1251822b0b40SSuryakanth Sekar } 1252822b0b40SSuryakanth Sekar else 1253822b0b40SSuryakanth Sekar { 1254822b0b40SSuryakanth Sekar if (specialUserIndex == 1255822b0b40SSuryakanth Sekar static_cast<uint8_t>(SpecialUserIndex::rootUser)) 1256822b0b40SSuryakanth Sekar { 1257822b0b40SSuryakanth Sekar status = executeCmd("passwd -d root"); 1258822b0b40SSuryakanth Sekar } 1259822b0b40SSuryakanth Sekar else 1260822b0b40SSuryakanth Sekar { 1261822b0b40SSuryakanth Sekar 1262822b0b40SSuryakanth Sekar status = executeCmd("passwd -d asdbg"); 1263822b0b40SSuryakanth Sekar 1264822b0b40SSuryakanth Sekar if (status == 0) 1265822b0b40SSuryakanth Sekar { 1266822b0b40SSuryakanth Sekar atScaleDebugEventlog("AtScaleDebugSpecialUserDisabled", 1267822b0b40SSuryakanth Sekar LOG_INFO); 1268822b0b40SSuryakanth Sekar } 1269822b0b40SSuryakanth Sekar } 1270822b0b40SSuryakanth Sekar return ipmi::response(status); 1271822b0b40SSuryakanth Sekar } 1272fc5e985bSRichard Marian Thomaiyar } 1273fc5e985bSRichard Marian Thomaiyar 127445f04988SKuiying Wang namespace ledAction 127545f04988SKuiying Wang { 127645f04988SKuiying Wang using namespace sdbusplus::xyz::openbmc_project::Led::server; 127745f04988SKuiying Wang std::map<Physical::Action, uint8_t> actionDbusToIpmi = { 1278934ee9c9Sjayaprakash Mutyala {Physical::Action::Off, 0}, 1279934ee9c9Sjayaprakash Mutyala {Physical::Action::On, 2}, 1280934ee9c9Sjayaprakash Mutyala {Physical::Action::Blink, 1}}; 128145f04988SKuiying Wang 128245f04988SKuiying Wang std::map<uint8_t, std::string> offsetObjPath = { 128345f04988SKuiying Wang {2, statusAmberObjPath}, {4, statusGreenObjPath}, {6, identifyLEDObjPath}}; 128445f04988SKuiying Wang 128545f04988SKuiying Wang } // namespace ledAction 128645f04988SKuiying Wang 128745f04988SKuiying Wang int8_t getLEDState(sdbusplus::bus::bus& bus, const std::string& intf, 128845f04988SKuiying Wang const std::string& objPath, uint8_t& state) 128945f04988SKuiying Wang { 129045f04988SKuiying Wang try 129145f04988SKuiying Wang { 129245f04988SKuiying Wang std::string service = getService(bus, intf, objPath); 129345f04988SKuiying Wang Value stateValue = 129445f04988SKuiying Wang getDbusProperty(bus, service, objPath, intf, "State"); 12958166c8d7SVernon Mauery std::string strState = std::get<std::string>(stateValue); 129645f04988SKuiying Wang state = ledAction::actionDbusToIpmi.at( 129745f04988SKuiying Wang sdbusplus::xyz::openbmc_project::Led::server::Physical:: 129845f04988SKuiying Wang convertActionFromString(strState)); 129945f04988SKuiying Wang } 130045f04988SKuiying Wang catch (sdbusplus::exception::SdBusError& e) 130145f04988SKuiying Wang { 130245f04988SKuiying Wang phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 130345f04988SKuiying Wang return -1; 130445f04988SKuiying Wang } 130545f04988SKuiying Wang return 0; 130645f04988SKuiying Wang } 130745f04988SKuiying Wang 1308abd11ca3SNITIN SHARMA ipmi::RspType<uint8_t> ipmiOEMGetLEDStatus() 130945f04988SKuiying Wang { 1310abd11ca3SNITIN SHARMA uint8_t ledstate = 0; 131145f04988SKuiying Wang phosphor::logging::log<phosphor::logging::level::DEBUG>("GET led status"); 131215419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 131345f04988SKuiying Wang for (auto it = ledAction::offsetObjPath.begin(); 131445f04988SKuiying Wang it != ledAction::offsetObjPath.end(); ++it) 131545f04988SKuiying Wang { 131645f04988SKuiying Wang uint8_t state = 0; 1317abd11ca3SNITIN SHARMA if (getLEDState(*dbus, ledIntf, it->second, state) == -1) 131845f04988SKuiying Wang { 131945f04988SKuiying Wang phosphor::logging::log<phosphor::logging::level::ERR>( 132045f04988SKuiying Wang "oem_get_led_status: fail to get ID LED status!"); 1321abd11ca3SNITIN SHARMA return ipmi::responseUnspecifiedError(); 132245f04988SKuiying Wang } 1323abd11ca3SNITIN SHARMA ledstate |= state << it->first; 132445f04988SKuiying Wang } 1325abd11ca3SNITIN SHARMA return ipmi::responseSuccess(ledstate); 132645f04988SKuiying Wang } 132745f04988SKuiying Wang 132823737fe3SYong Li ipmi_ret_t ipmiOEMCfgHostSerialPortSpeed(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 132923737fe3SYong Li ipmi_request_t request, 133023737fe3SYong Li ipmi_response_t response, 133123737fe3SYong Li ipmi_data_len_t dataLen, 133223737fe3SYong Li ipmi_context_t context) 133323737fe3SYong Li { 133423737fe3SYong Li CfgHostSerialReq* req = reinterpret_cast<CfgHostSerialReq*>(request); 133523737fe3SYong Li uint8_t* resp = reinterpret_cast<uint8_t*>(response); 133623737fe3SYong Li 133723737fe3SYong Li if (*dataLen == 0) 133823737fe3SYong Li { 133923737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 134023737fe3SYong Li "CfgHostSerial: invalid input len!", 134123737fe3SYong Li phosphor::logging::entry("LEN=%d", *dataLen)); 134223737fe3SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 134323737fe3SYong Li } 134423737fe3SYong Li 134523737fe3SYong Li switch (req->command) 134623737fe3SYong Li { 134723737fe3SYong Li case getHostSerialCfgCmd: 134823737fe3SYong Li { 134923737fe3SYong Li if (*dataLen != 1) 135023737fe3SYong Li { 135123737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 135223737fe3SYong Li "CfgHostSerial: invalid input len!"); 135323737fe3SYong Li *dataLen = 0; 135423737fe3SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 135523737fe3SYong Li } 135623737fe3SYong Li 135723737fe3SYong Li *dataLen = 0; 135823737fe3SYong Li 135923737fe3SYong Li boost::process::ipstream is; 136023737fe3SYong Li std::vector<std::string> data; 136123737fe3SYong Li std::string line; 136223737fe3SYong Li boost::process::child c1(fwGetEnvCmd, "-n", fwHostSerailCfgEnvName, 136323737fe3SYong Li boost::process::std_out > is); 136423737fe3SYong Li 136523737fe3SYong Li while (c1.running() && std::getline(is, line) && !line.empty()) 136623737fe3SYong Li { 136723737fe3SYong Li data.push_back(line); 136823737fe3SYong Li } 136923737fe3SYong Li 137023737fe3SYong Li c1.wait(); 137123737fe3SYong Li if (c1.exit_code()) 137223737fe3SYong Li { 137323737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 137423737fe3SYong Li "CfgHostSerial:: error on execute", 137523737fe3SYong Li phosphor::logging::entry("EXECUTE=%s", fwSetEnvCmd)); 137623737fe3SYong Li // Using the default value 137723737fe3SYong Li *resp = 0; 137823737fe3SYong Li } 137923737fe3SYong Li else 138023737fe3SYong Li { 138123737fe3SYong Li if (data.size() != 1) 138223737fe3SYong Li { 138323737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 138423737fe3SYong Li "CfgHostSerial:: error on read env"); 138523737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 138623737fe3SYong Li } 138723737fe3SYong Li try 138823737fe3SYong Li { 138923737fe3SYong Li unsigned long tmp = std::stoul(data[0]); 139023737fe3SYong Li if (tmp > std::numeric_limits<uint8_t>::max()) 139123737fe3SYong Li { 139223737fe3SYong Li throw std::out_of_range("Out of range"); 139323737fe3SYong Li } 139423737fe3SYong Li *resp = static_cast<uint8_t>(tmp); 139523737fe3SYong Li } 139623737fe3SYong Li catch (const std::invalid_argument& e) 139723737fe3SYong Li { 139823737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 139923737fe3SYong Li "invalid config ", 140023737fe3SYong Li phosphor::logging::entry("ERR=%s", e.what())); 140123737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 140223737fe3SYong Li } 140323737fe3SYong Li catch (const std::out_of_range& e) 140423737fe3SYong Li { 140523737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 140623737fe3SYong Li "out_of_range config ", 140723737fe3SYong Li phosphor::logging::entry("ERR=%s", e.what())); 140823737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 140923737fe3SYong Li } 141023737fe3SYong Li } 141123737fe3SYong Li 141223737fe3SYong Li *dataLen = 1; 141323737fe3SYong Li break; 141423737fe3SYong Li } 141523737fe3SYong Li case setHostSerialCfgCmd: 141623737fe3SYong Li { 141723737fe3SYong Li if (*dataLen != sizeof(CfgHostSerialReq)) 141823737fe3SYong Li { 141923737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 142023737fe3SYong Li "CfgHostSerial: invalid input len!"); 142123737fe3SYong Li *dataLen = 0; 142223737fe3SYong Li return IPMI_CC_REQ_DATA_LEN_INVALID; 142323737fe3SYong Li } 142423737fe3SYong Li 142523737fe3SYong Li *dataLen = 0; 142623737fe3SYong Li 142723737fe3SYong Li if (req->parameter > HostSerialCfgParamMax) 142823737fe3SYong Li { 142923737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 143023737fe3SYong Li "CfgHostSerial: invalid input!"); 143123737fe3SYong Li return IPMI_CC_INVALID_FIELD_REQUEST; 143223737fe3SYong Li } 143323737fe3SYong Li 143423737fe3SYong Li boost::process::child c1(fwSetEnvCmd, fwHostSerailCfgEnvName, 143523737fe3SYong Li std::to_string(req->parameter)); 143623737fe3SYong Li 143723737fe3SYong Li c1.wait(); 143823737fe3SYong Li if (c1.exit_code()) 143923737fe3SYong Li { 144023737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 144123737fe3SYong Li "CfgHostSerial:: error on execute", 144223737fe3SYong Li phosphor::logging::entry("EXECUTE=%s", fwGetEnvCmd)); 144323737fe3SYong Li return IPMI_CC_UNSPECIFIED_ERROR; 144423737fe3SYong Li } 144523737fe3SYong Li break; 144623737fe3SYong Li } 144723737fe3SYong Li default: 144823737fe3SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 144923737fe3SYong Li "CfgHostSerial: invalid input!"); 145023737fe3SYong Li *dataLen = 0; 145123737fe3SYong Li return IPMI_CC_INVALID_FIELD_REQUEST; 145223737fe3SYong Li } 145323737fe3SYong Li 145423737fe3SYong Li return IPMI_CC_OK; 145523737fe3SYong Li } 145623737fe3SYong Li 145791244a6aSJames Feist constexpr const char* thermalModeInterface = 145891244a6aSJames Feist "xyz.openbmc_project.Control.ThermalMode"; 145991244a6aSJames Feist constexpr const char* thermalModePath = 146091244a6aSJames Feist "/xyz/openbmc_project/control/thermal_mode"; 146191244a6aSJames Feist 146291244a6aSJames Feist bool getFanProfileInterface( 146391244a6aSJames Feist sdbusplus::bus::bus& bus, 146491244a6aSJames Feist boost::container::flat_map< 146591244a6aSJames Feist std::string, std::variant<std::vector<std::string>, std::string>>& resp) 146691244a6aSJames Feist { 146791244a6aSJames Feist auto call = bus.new_method_call(settingsBusName, thermalModePath, PROP_INTF, 146891244a6aSJames Feist "GetAll"); 146991244a6aSJames Feist call.append(thermalModeInterface); 147091244a6aSJames Feist try 147191244a6aSJames Feist { 147291244a6aSJames Feist auto data = bus.call(call); 147391244a6aSJames Feist data.read(resp); 147491244a6aSJames Feist } 147591244a6aSJames Feist catch (sdbusplus::exception_t& e) 147691244a6aSJames Feist { 147791244a6aSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 147891244a6aSJames Feist "getFanProfileInterface: can't get thermal mode!", 147991244a6aSJames Feist phosphor::logging::entry("ERR=%s", e.what())); 148091244a6aSJames Feist return false; 148191244a6aSJames Feist } 148291244a6aSJames Feist return true; 148391244a6aSJames Feist } 148491244a6aSJames Feist 1485f945eee0Sanil kumar appana /**@brief implements the OEM set fan config. 1486f945eee0Sanil kumar appana * @param selectedFanProfile - fan profile to enable 1487f945eee0Sanil kumar appana * @param reserved1 1488f945eee0Sanil kumar appana * @param performanceMode - Performance/Acoustic mode 1489f945eee0Sanil kumar appana * @param reserved2 1490f945eee0Sanil kumar appana * @param setPerformanceMode - set Performance/Acoustic mode 1491f945eee0Sanil kumar appana * @param setFanProfile - set fan profile 1492f945eee0Sanil kumar appana * 1493f945eee0Sanil kumar appana * @return IPMI completion code. 1494f945eee0Sanil kumar appana **/ 1495f945eee0Sanil kumar appana ipmi::RspType<> ipmiOEMSetFanConfig(uint8_t selectedFanProfile, 149691244a6aSJames Feist 1497f945eee0Sanil kumar appana uint2_t reserved1, bool performanceMode, 1498f945eee0Sanil kumar appana uint3_t reserved2, bool setPerformanceMode, 1499619186dbSJoshi-Mansi bool setFanProfile, 1500619186dbSJoshi-Mansi std::optional<uint8_t> dimmGroupId, 1501619186dbSJoshi-Mansi std::optional<uint32_t> dimmPresenceBitmap) 150291244a6aSJames Feist { 1503f945eee0Sanil kumar appana if (reserved1 || reserved2) 1504f945eee0Sanil kumar appana { 1505f945eee0Sanil kumar appana return ipmi::responseInvalidFieldRequest(); 150691244a6aSJames Feist } 1507619186dbSJoshi-Mansi 1508619186dbSJoshi-Mansi if (dimmGroupId) 1509619186dbSJoshi-Mansi { 1510619186dbSJoshi-Mansi if (*dimmGroupId >= maxCPUNum) 1511619186dbSJoshi-Mansi { 1512619186dbSJoshi-Mansi return ipmi::responseInvalidFieldRequest(); 1513619186dbSJoshi-Mansi } 1514619186dbSJoshi-Mansi if (!cpuPresent("CPU_" + std::to_string(*dimmGroupId + 1))) 1515619186dbSJoshi-Mansi { 1516619186dbSJoshi-Mansi return ipmi::responseInvalidFieldRequest(); 1517619186dbSJoshi-Mansi } 1518619186dbSJoshi-Mansi } 1519619186dbSJoshi-Mansi 152091244a6aSJames Feist // todo: tell bios to only send first 2 bytes 152191244a6aSJames Feist boost::container::flat_map< 152291244a6aSJames Feist std::string, std::variant<std::vector<std::string>, std::string>> 152391244a6aSJames Feist profileData; 152415419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 152515419dd5SVernon Mauery if (!getFanProfileInterface(*dbus, profileData)) 152691244a6aSJames Feist { 1527f945eee0Sanil kumar appana return ipmi::responseUnspecifiedError(); 152891244a6aSJames Feist } 152991244a6aSJames Feist 153091244a6aSJames Feist std::vector<std::string>* supported = 153191244a6aSJames Feist std::get_if<std::vector<std::string>>(&profileData["Supported"]); 153291244a6aSJames Feist if (supported == nullptr) 153391244a6aSJames Feist { 1534f945eee0Sanil kumar appana return ipmi::responseInvalidFieldRequest(); 153591244a6aSJames Feist } 153691244a6aSJames Feist std::string mode; 1537f945eee0Sanil kumar appana if (setPerformanceMode) 153891244a6aSJames Feist { 153991244a6aSJames Feist if (performanceMode) 154091244a6aSJames Feist { 154191244a6aSJames Feist 154291244a6aSJames Feist if (std::find(supported->begin(), supported->end(), 154391244a6aSJames Feist "Performance") != supported->end()) 154491244a6aSJames Feist { 154591244a6aSJames Feist mode = "Performance"; 154691244a6aSJames Feist } 154791244a6aSJames Feist } 154891244a6aSJames Feist else 154991244a6aSJames Feist { 155091244a6aSJames Feist if (std::find(supported->begin(), supported->end(), "Acoustic") != 155191244a6aSJames Feist supported->end()) 155291244a6aSJames Feist { 155391244a6aSJames Feist mode = "Acoustic"; 155491244a6aSJames Feist } 155591244a6aSJames Feist } 155691244a6aSJames Feist if (mode.empty()) 155791244a6aSJames Feist { 1558f945eee0Sanil kumar appana return ipmi::responseInvalidFieldRequest(); 155991244a6aSJames Feist } 1560f945eee0Sanil kumar appana 1561f945eee0Sanil kumar appana try 1562f945eee0Sanil kumar appana { 156315419dd5SVernon Mauery setDbusProperty(*dbus, settingsBusName, thermalModePath, 156491244a6aSJames Feist thermalModeInterface, "Current", mode); 156591244a6aSJames Feist } 1566f945eee0Sanil kumar appana catch (sdbusplus::exception_t& e) 1567f945eee0Sanil kumar appana { 1568f945eee0Sanil kumar appana phosphor::logging::log<phosphor::logging::level::ERR>( 1569f945eee0Sanil kumar appana "ipmiOEMSetFanConfig: can't set thermal mode!", 1570f945eee0Sanil kumar appana phosphor::logging::entry("EXCEPTION=%s", e.what())); 1571f945eee0Sanil kumar appana return ipmi::responseResponseError(); 1572f945eee0Sanil kumar appana } 1573f945eee0Sanil kumar appana } 157491244a6aSJames Feist 1575f945eee0Sanil kumar appana return ipmi::responseSuccess(); 157691244a6aSJames Feist } 157791244a6aSJames Feist 15785b693637SJames Feist ipmi::RspType<uint8_t, // profile support map 15795b693637SJames Feist uint8_t, // fan control profile enable 15805b693637SJames Feist uint8_t, // flags 15815b693637SJames Feist uint32_t // dimm presence bit map 15825b693637SJames Feist > 15835b693637SJames Feist ipmiOEMGetFanConfig(uint8_t dimmGroupId) 158491244a6aSJames Feist { 158536f05ce6SJoshi-Mansi if (dimmGroupId >= maxCPUNum) 158636f05ce6SJoshi-Mansi { 158736f05ce6SJoshi-Mansi return ipmi::responseInvalidFieldRequest(); 158836f05ce6SJoshi-Mansi } 158936f05ce6SJoshi-Mansi 159036f05ce6SJoshi-Mansi bool cpuStatus = cpuPresent("CPU_" + std::to_string(dimmGroupId + 1)); 159136f05ce6SJoshi-Mansi 159236f05ce6SJoshi-Mansi if (!cpuStatus) 159336f05ce6SJoshi-Mansi { 159436f05ce6SJoshi-Mansi return ipmi::responseInvalidFieldRequest(); 159536f05ce6SJoshi-Mansi } 159636f05ce6SJoshi-Mansi 159791244a6aSJames Feist boost::container::flat_map< 159891244a6aSJames Feist std::string, std::variant<std::vector<std::string>, std::string>> 159991244a6aSJames Feist profileData; 160091244a6aSJames Feist 160115419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 160215419dd5SVernon Mauery if (!getFanProfileInterface(*dbus, profileData)) 160391244a6aSJames Feist { 16045b693637SJames Feist return ipmi::responseResponseError(); 160591244a6aSJames Feist } 160691244a6aSJames Feist 160791244a6aSJames Feist std::string* current = std::get_if<std::string>(&profileData["Current"]); 160891244a6aSJames Feist 160991244a6aSJames Feist if (current == nullptr) 161091244a6aSJames Feist { 161191244a6aSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 161291244a6aSJames Feist "ipmiOEMGetFanConfig: can't get current mode!"); 16135b693637SJames Feist return ipmi::responseResponseError(); 161491244a6aSJames Feist } 161591244a6aSJames Feist bool performance = (*current == "Performance"); 161691244a6aSJames Feist 16175b693637SJames Feist uint8_t flags = 0; 161891244a6aSJames Feist if (performance) 161991244a6aSJames Feist { 16205b693637SJames Feist flags |= 1 << 2; 162191244a6aSJames Feist } 162291244a6aSJames Feist 16234b1552d8Sjayaprakash Mutyala constexpr uint8_t fanControlDefaultProfile = 0x80; 16244b1552d8Sjayaprakash Mutyala constexpr uint8_t fanControlProfileState = 0x00; 16254b1552d8Sjayaprakash Mutyala constexpr uint32_t dimmPresenceBitmap = 0x00; 16264b1552d8Sjayaprakash Mutyala 16274b1552d8Sjayaprakash Mutyala return ipmi::responseSuccess(fanControlDefaultProfile, 16284b1552d8Sjayaprakash Mutyala fanControlProfileState, flags, 16294b1552d8Sjayaprakash Mutyala dimmPresenceBitmap); 163091244a6aSJames Feist } 16315f957cafSJames Feist constexpr const char* cfmLimitSettingPath = 16325f957cafSJames Feist "/xyz/openbmc_project/control/cfm_limit"; 16335f957cafSJames Feist constexpr const char* cfmLimitIface = "xyz.openbmc_project.Control.CFMLimit"; 1634faa4f223SJames Feist constexpr const size_t legacyExitAirSensorNumber = 0x2e; 163509f6b604SJames Feist constexpr const size_t legacyPCHSensorNumber = 0x22; 163609f6b604SJames Feist constexpr const char* exitAirPathName = "Exit_Air"; 163709f6b604SJames Feist constexpr const char* pchPathName = "SSB_Temp"; 1638acc8a4ebSJames Feist constexpr const char* pidConfigurationIface = 1639acc8a4ebSJames Feist "xyz.openbmc_project.Configuration.Pid"; 1640faa4f223SJames Feist 164109f6b604SJames Feist static std::string getConfigPath(const std::string& name) 1642faa4f223SJames Feist { 164315419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1644faa4f223SJames Feist auto method = 164515419dd5SVernon Mauery dbus->new_method_call("xyz.openbmc_project.ObjectMapper", 1646faa4f223SJames Feist "/xyz/openbmc_project/object_mapper", 1647faa4f223SJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1648faa4f223SJames Feist 1649acc8a4ebSJames Feist method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1650faa4f223SJames Feist std::string path; 1651faa4f223SJames Feist GetSubTreeType resp; 1652faa4f223SJames Feist try 1653faa4f223SJames Feist { 165415419dd5SVernon Mauery auto reply = dbus->call(method); 1655faa4f223SJames Feist reply.read(resp); 1656faa4f223SJames Feist } 1657faa4f223SJames Feist catch (sdbusplus::exception_t&) 1658faa4f223SJames Feist { 1659faa4f223SJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1660faa4f223SJames Feist "ipmiOEMGetFscParameter: mapper error"); 1661faa4f223SJames Feist }; 166209f6b604SJames Feist auto config = 166309f6b604SJames Feist std::find_if(resp.begin(), resp.end(), [&name](const auto& pair) { 166409f6b604SJames Feist return pair.first.find(name) != std::string::npos; 1665faa4f223SJames Feist }); 1666faa4f223SJames Feist if (config != resp.end()) 1667faa4f223SJames Feist { 1668faa4f223SJames Feist path = std::move(config->first); 1669faa4f223SJames Feist } 1670faa4f223SJames Feist return path; 1671faa4f223SJames Feist } 16725f957cafSJames Feist 1673acc8a4ebSJames Feist // flat map to make alphabetical 1674acc8a4ebSJames Feist static boost::container::flat_map<std::string, PropertyMap> getPidConfigs() 1675acc8a4ebSJames Feist { 1676acc8a4ebSJames Feist boost::container::flat_map<std::string, PropertyMap> ret; 167715419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1678acc8a4ebSJames Feist auto method = 167915419dd5SVernon Mauery dbus->new_method_call("xyz.openbmc_project.ObjectMapper", 1680acc8a4ebSJames Feist "/xyz/openbmc_project/object_mapper", 1681acc8a4ebSJames Feist "xyz.openbmc_project.ObjectMapper", "GetSubTree"); 1682acc8a4ebSJames Feist 1683acc8a4ebSJames Feist method.append("/", 0, std::array<const char*, 1>{pidConfigurationIface}); 1684acc8a4ebSJames Feist GetSubTreeType resp; 1685acc8a4ebSJames Feist 1686acc8a4ebSJames Feist try 1687acc8a4ebSJames Feist { 168815419dd5SVernon Mauery auto reply = dbus->call(method); 1689acc8a4ebSJames Feist reply.read(resp); 1690acc8a4ebSJames Feist } 1691acc8a4ebSJames Feist catch (sdbusplus::exception_t&) 1692acc8a4ebSJames Feist { 1693acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1694acc8a4ebSJames Feist "getFanConfigPaths: mapper error"); 1695acc8a4ebSJames Feist }; 1696acc8a4ebSJames Feist for (const auto& [path, objects] : resp) 1697acc8a4ebSJames Feist { 1698acc8a4ebSJames Feist if (objects.empty()) 1699acc8a4ebSJames Feist { 1700acc8a4ebSJames Feist continue; // should be impossible 1701acc8a4ebSJames Feist } 1702be560b09SZhu, Yunge 1703be560b09SZhu, Yunge try 1704be560b09SZhu, Yunge { 170515419dd5SVernon Mauery ret.emplace(path, 170615419dd5SVernon Mauery getAllDbusProperties(*dbus, objects[0].first, path, 1707acc8a4ebSJames Feist pidConfigurationIface)); 1708acc8a4ebSJames Feist } 1709be560b09SZhu, Yunge catch (sdbusplus::exception_t& e) 1710be560b09SZhu, Yunge { 1711be560b09SZhu, Yunge phosphor::logging::log<phosphor::logging::level::ERR>( 1712be560b09SZhu, Yunge "getPidConfigs: can't get DbusProperties!", 1713be560b09SZhu, Yunge phosphor::logging::entry("ERR=%s", e.what())); 1714be560b09SZhu, Yunge } 1715be560b09SZhu, Yunge } 1716acc8a4ebSJames Feist return ret; 1717acc8a4ebSJames Feist } 1718acc8a4ebSJames Feist 1719acc8a4ebSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetFanSpeedOffset(void) 1720acc8a4ebSJames Feist { 1721acc8a4ebSJames Feist boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1722acc8a4ebSJames Feist if (data.empty()) 1723acc8a4ebSJames Feist { 1724acc8a4ebSJames Feist return ipmi::responseResponseError(); 1725acc8a4ebSJames Feist } 1726acc8a4ebSJames Feist uint8_t minOffset = std::numeric_limits<uint8_t>::max(); 1727acc8a4ebSJames Feist for (const auto& [_, pid] : data) 1728acc8a4ebSJames Feist { 1729acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1730acc8a4ebSJames Feist if (findClass == pid.end()) 1731acc8a4ebSJames Feist { 1732acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1733acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 1734acc8a4ebSJames Feist "configurations"); 1735acc8a4ebSJames Feist return ipmi::responseResponseError(); 1736acc8a4ebSJames Feist } 1737acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1738acc8a4ebSJames Feist if (type == "fan") 1739acc8a4ebSJames Feist { 1740acc8a4ebSJames Feist auto findOutLimit = pid.find("OutLimitMin"); 1741acc8a4ebSJames Feist if (findOutLimit == pid.end()) 1742acc8a4ebSJames Feist { 1743acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1744acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 1745acc8a4ebSJames Feist "configurations"); 1746acc8a4ebSJames Feist return ipmi::responseResponseError(); 1747acc8a4ebSJames Feist } 1748acc8a4ebSJames Feist // get the min out of all the offsets 1749acc8a4ebSJames Feist minOffset = std::min( 1750acc8a4ebSJames Feist minOffset, 1751acc8a4ebSJames Feist static_cast<uint8_t>(std::get<double>(findOutLimit->second))); 1752acc8a4ebSJames Feist } 1753acc8a4ebSJames Feist } 1754acc8a4ebSJames Feist if (minOffset == std::numeric_limits<uint8_t>::max()) 1755acc8a4ebSJames Feist { 1756acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1757acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found no fan configurations!"); 1758acc8a4ebSJames Feist return ipmi::responseResponseError(); 1759acc8a4ebSJames Feist } 1760acc8a4ebSJames Feist 1761acc8a4ebSJames Feist return ipmi::responseSuccess(minOffset); 1762acc8a4ebSJames Feist } 1763acc8a4ebSJames Feist 1764acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFanSpeedOffset(uint8_t offset) 1765acc8a4ebSJames Feist { 1766acc8a4ebSJames Feist boost::container::flat_map<std::string, PropertyMap> data = getPidConfigs(); 1767acc8a4ebSJames Feist if (data.empty()) 1768acc8a4ebSJames Feist { 1769acc8a4ebSJames Feist 1770acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1771acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: found no pid configurations!"); 1772acc8a4ebSJames Feist return ipmi::responseResponseError(); 1773acc8a4ebSJames Feist } 1774acc8a4ebSJames Feist 177515419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1776acc8a4ebSJames Feist bool found = false; 1777acc8a4ebSJames Feist for (const auto& [path, pid] : data) 1778acc8a4ebSJames Feist { 1779acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1780acc8a4ebSJames Feist if (findClass == pid.end()) 1781acc8a4ebSJames Feist { 1782acc8a4ebSJames Feist 1783acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1784acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: found illegal pid " 1785acc8a4ebSJames Feist "configurations"); 1786acc8a4ebSJames Feist return ipmi::responseResponseError(); 1787acc8a4ebSJames Feist } 1788acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1789acc8a4ebSJames Feist if (type == "fan") 1790acc8a4ebSJames Feist { 1791acc8a4ebSJames Feist auto findOutLimit = pid.find("OutLimitMin"); 1792acc8a4ebSJames Feist if (findOutLimit == pid.end()) 1793acc8a4ebSJames Feist { 1794acc8a4ebSJames Feist 1795acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1796acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: found illegal pid " 1797acc8a4ebSJames Feist "configurations"); 1798acc8a4ebSJames Feist return ipmi::responseResponseError(); 1799acc8a4ebSJames Feist } 180015419dd5SVernon Mauery ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", 1801acc8a4ebSJames Feist path, pidConfigurationIface, "OutLimitMin", 1802acc8a4ebSJames Feist static_cast<double>(offset)); 1803acc8a4ebSJames Feist found = true; 1804acc8a4ebSJames Feist } 1805acc8a4ebSJames Feist } 1806acc8a4ebSJames Feist if (!found) 1807acc8a4ebSJames Feist { 1808acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1809acc8a4ebSJames Feist "ipmiOEMSetFanSpeedOffset: set no fan offsets"); 1810acc8a4ebSJames Feist return ipmi::responseResponseError(); 1811acc8a4ebSJames Feist } 1812acc8a4ebSJames Feist 1813acc8a4ebSJames Feist return ipmi::responseSuccess(); 1814acc8a4ebSJames Feist } 1815acc8a4ebSJames Feist 1816acc8a4ebSJames Feist ipmi::RspType<> ipmiOEMSetFscParameter(uint8_t command, uint8_t param1, 1817acc8a4ebSJames Feist uint8_t param2) 18185f957cafSJames Feist { 18195f957cafSJames Feist constexpr const size_t disableLimiting = 0x0; 18205f957cafSJames Feist 182115419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1822acc8a4ebSJames Feist if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 18235f957cafSJames Feist { 182409f6b604SJames Feist std::string pathName; 1825acc8a4ebSJames Feist if (param1 == legacyExitAirSensorNumber) 1826faa4f223SJames Feist { 182709f6b604SJames Feist pathName = exitAirPathName; 182809f6b604SJames Feist } 182909f6b604SJames Feist else if (param1 == legacyPCHSensorNumber) 183009f6b604SJames Feist { 183109f6b604SJames Feist pathName = pchPathName; 1832faa4f223SJames Feist } 1833faa4f223SJames Feist else 1834faa4f223SJames Feist { 1835acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 1836faa4f223SJames Feist } 183709f6b604SJames Feist std::string path = getConfigPath(pathName); 183809f6b604SJames Feist ipmi::setDbusProperty(*dbus, "xyz.openbmc_project.EntityManager", path, 183909f6b604SJames Feist pidConfigurationIface, "SetPoint", 184009f6b604SJames Feist static_cast<double>(param2)); 184109f6b604SJames Feist return ipmi::responseSuccess(); 1842faa4f223SJames Feist } 1843acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 18445f957cafSJames Feist { 1845acc8a4ebSJames Feist uint16_t cfm = param1 | (static_cast<uint16_t>(param2) << 8); 18465f957cafSJames Feist 18475f957cafSJames Feist // must be greater than 50 based on eps 18485f957cafSJames Feist if (cfm < 50 && cfm != disableLimiting) 18495f957cafSJames Feist { 1850acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 18515f957cafSJames Feist } 18525f957cafSJames Feist 18535f957cafSJames Feist try 18545f957cafSJames Feist { 185515419dd5SVernon Mauery ipmi::setDbusProperty(*dbus, settingsBusName, cfmLimitSettingPath, 18565f957cafSJames Feist cfmLimitIface, "Limit", 18575f957cafSJames Feist static_cast<double>(cfm)); 18585f957cafSJames Feist } 18595f957cafSJames Feist catch (sdbusplus::exception_t& e) 18605f957cafSJames Feist { 18615f957cafSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 18625f957cafSJames Feist "ipmiOEMSetFscParameter: can't set cfm setting!", 18635f957cafSJames Feist phosphor::logging::entry("ERR=%s", e.what())); 1864acc8a4ebSJames Feist return ipmi::responseResponseError(); 18655f957cafSJames Feist } 1866acc8a4ebSJames Feist return ipmi::responseSuccess(); 1867acc8a4ebSJames Feist } 1868acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1869acc8a4ebSJames Feist { 1870acc8a4ebSJames Feist constexpr const size_t maxDomainCount = 8; 1871acc8a4ebSJames Feist uint8_t requestedDomainMask = param1; 1872acc8a4ebSJames Feist boost::container::flat_map data = getPidConfigs(); 1873acc8a4ebSJames Feist if (data.empty()) 1874acc8a4ebSJames Feist { 1875acc8a4ebSJames Feist 1876acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1877acc8a4ebSJames Feist "ipmiOEMSetFscParameter: found no pid configurations!"); 1878acc8a4ebSJames Feist return ipmi::responseResponseError(); 1879acc8a4ebSJames Feist } 1880acc8a4ebSJames Feist size_t count = 0; 1881acc8a4ebSJames Feist for (const auto& [path, pid] : data) 1882acc8a4ebSJames Feist { 1883acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1884acc8a4ebSJames Feist if (findClass == pid.end()) 1885acc8a4ebSJames Feist { 1886acc8a4ebSJames Feist 1887acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1888acc8a4ebSJames Feist "ipmiOEMSetFscParameter: found illegal pid " 1889acc8a4ebSJames Feist "configurations"); 1890acc8a4ebSJames Feist return ipmi::responseResponseError(); 1891acc8a4ebSJames Feist } 1892acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1893acc8a4ebSJames Feist if (type == "fan") 1894acc8a4ebSJames Feist { 1895acc8a4ebSJames Feist if (requestedDomainMask & (1 << count)) 1896acc8a4ebSJames Feist { 1897acc8a4ebSJames Feist ipmi::setDbusProperty( 189815419dd5SVernon Mauery *dbus, "xyz.openbmc_project.EntityManager", path, 1899acc8a4ebSJames Feist pidConfigurationIface, "OutLimitMax", 1900acc8a4ebSJames Feist static_cast<double>(param2)); 1901acc8a4ebSJames Feist } 1902acc8a4ebSJames Feist count++; 1903acc8a4ebSJames Feist } 1904acc8a4ebSJames Feist } 1905acc8a4ebSJames Feist return ipmi::responseSuccess(); 19065f957cafSJames Feist } 19075f957cafSJames Feist else 19085f957cafSJames Feist { 19095f957cafSJames Feist // todo other command parts possibly 19105f957cafSJames Feist // tcontrol is handled in peci now 19115f957cafSJames Feist // fan speed offset not implemented yet 19125f957cafSJames Feist // domain pwm limit not implemented 1913acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 19145f957cafSJames Feist } 19155f957cafSJames Feist } 19165f957cafSJames Feist 1917acc8a4ebSJames Feist ipmi::RspType< 1918acc8a4ebSJames Feist std::variant<uint8_t, std::array<uint8_t, 2>, std::array<uint16_t, 2>>> 1919acc8a4ebSJames Feist ipmiOEMGetFscParameter(uint8_t command, std::optional<uint8_t> param) 19205f957cafSJames Feist { 192109f6b604SJames Feist constexpr uint8_t legacyDefaultSetpoint = -128; 19225f957cafSJames Feist 192315419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 1924acc8a4ebSJames Feist if (command == static_cast<uint8_t>(setFscParamFlags::tcontrol)) 19255f957cafSJames Feist { 1926acc8a4ebSJames Feist if (!param) 1927acc8a4ebSJames Feist { 1928acc8a4ebSJames Feist return ipmi::responseReqDataLenInvalid(); 19295f957cafSJames Feist } 19305f957cafSJames Feist 193109f6b604SJames Feist std::string pathName; 193209f6b604SJames Feist 193309f6b604SJames Feist if (*param == legacyExitAirSensorNumber) 193409f6b604SJames Feist { 193509f6b604SJames Feist pathName = exitAirPathName; 193609f6b604SJames Feist } 193709f6b604SJames Feist else if (*param == legacyPCHSensorNumber) 193809f6b604SJames Feist { 193909f6b604SJames Feist pathName = pchPathName; 194009f6b604SJames Feist } 194109f6b604SJames Feist else 1942faa4f223SJames Feist { 1943acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 1944faa4f223SJames Feist } 194509f6b604SJames Feist 194609f6b604SJames Feist uint8_t setpoint = legacyDefaultSetpoint; 194709f6b604SJames Feist std::string path = getConfigPath(pathName); 1948faa4f223SJames Feist if (path.size()) 1949faa4f223SJames Feist { 195015419dd5SVernon Mauery Value val = ipmi::getDbusProperty( 195115419dd5SVernon Mauery *dbus, "xyz.openbmc_project.EntityManager", path, 195215419dd5SVernon Mauery pidConfigurationIface, "SetPoint"); 1953faa4f223SJames Feist setpoint = std::floor(std::get<double>(val) + 0.5); 1954faa4f223SJames Feist } 1955faa4f223SJames Feist 1956faa4f223SJames Feist // old implementation used to return the "default" and current, we 1957faa4f223SJames Feist // don't make the default readily available so just make both the 1958faa4f223SJames Feist // same 1959faa4f223SJames Feist 1960acc8a4ebSJames Feist return ipmi::responseSuccess( 1961acc8a4ebSJames Feist std::array<uint8_t, 2>{setpoint, setpoint}); 1962faa4f223SJames Feist } 1963acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::maxPwm)) 1964acc8a4ebSJames Feist { 1965acc8a4ebSJames Feist constexpr const size_t maxDomainCount = 8; 1966acc8a4ebSJames Feist 1967acc8a4ebSJames Feist if (!param) 1968acc8a4ebSJames Feist { 1969acc8a4ebSJames Feist return ipmi::responseReqDataLenInvalid(); 1970acc8a4ebSJames Feist } 1971acc8a4ebSJames Feist uint8_t requestedDomain = *param; 1972acc8a4ebSJames Feist if (requestedDomain >= maxDomainCount) 1973acc8a4ebSJames Feist { 1974acc8a4ebSJames Feist return ipmi::responseInvalidFieldRequest(); 1975acc8a4ebSJames Feist } 1976acc8a4ebSJames Feist 1977acc8a4ebSJames Feist boost::container::flat_map data = getPidConfigs(); 1978acc8a4ebSJames Feist if (data.empty()) 1979acc8a4ebSJames Feist { 1980acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1981acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found no pid configurations!"); 1982acc8a4ebSJames Feist return ipmi::responseResponseError(); 1983acc8a4ebSJames Feist } 1984acc8a4ebSJames Feist size_t count = 0; 1985acc8a4ebSJames Feist for (const auto& [_, pid] : data) 1986acc8a4ebSJames Feist { 1987acc8a4ebSJames Feist auto findClass = pid.find("Class"); 1988acc8a4ebSJames Feist if (findClass == pid.end()) 1989acc8a4ebSJames Feist { 1990acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 1991acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 1992acc8a4ebSJames Feist "configurations"); 1993acc8a4ebSJames Feist return ipmi::responseResponseError(); 1994acc8a4ebSJames Feist } 1995acc8a4ebSJames Feist std::string type = std::get<std::string>(findClass->second); 1996acc8a4ebSJames Feist if (type == "fan") 1997acc8a4ebSJames Feist { 1998acc8a4ebSJames Feist if (requestedDomain == count) 1999acc8a4ebSJames Feist { 2000acc8a4ebSJames Feist auto findOutLimit = pid.find("OutLimitMax"); 2001acc8a4ebSJames Feist if (findOutLimit == pid.end()) 2002acc8a4ebSJames Feist { 2003acc8a4ebSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 2004acc8a4ebSJames Feist "ipmiOEMGetFscParameter: found illegal pid " 2005acc8a4ebSJames Feist "configurations"); 2006acc8a4ebSJames Feist return ipmi::responseResponseError(); 2007acc8a4ebSJames Feist } 2008acc8a4ebSJames Feist 2009acc8a4ebSJames Feist return ipmi::responseSuccess( 2010acc8a4ebSJames Feist static_cast<uint8_t>(std::floor( 2011acc8a4ebSJames Feist std::get<double>(findOutLimit->second) + 0.5))); 2012acc8a4ebSJames Feist } 2013acc8a4ebSJames Feist else 2014acc8a4ebSJames Feist { 2015acc8a4ebSJames Feist count++; 2016acc8a4ebSJames Feist } 2017acc8a4ebSJames Feist } 2018acc8a4ebSJames Feist } 2019acc8a4ebSJames Feist 2020acc8a4ebSJames Feist return ipmi::responseInvalidFieldRequest(); 2021acc8a4ebSJames Feist } 2022acc8a4ebSJames Feist else if (command == static_cast<uint8_t>(setFscParamFlags::cfm)) 20235f957cafSJames Feist { 20245f957cafSJames Feist 20255f957cafSJames Feist /* 20265f957cafSJames Feist DataLen should be 1, but host is sending us an extra bit. As the 2027acc8a4ebSJames Feist previous behavior didn't seem to prevent this, ignore the check for 2028acc8a4ebSJames Feist now. 20295f957cafSJames Feist 2030acc8a4ebSJames Feist if (param) 20315f957cafSJames Feist { 20325f957cafSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 20335f957cafSJames Feist "ipmiOEMGetFscParameter: invalid input len!"); 20345f957cafSJames Feist return IPMI_CC_REQ_DATA_LEN_INVALID; 20355f957cafSJames Feist } 20365f957cafSJames Feist */ 20375f957cafSJames Feist Value cfmLimit; 20385f957cafSJames Feist Value cfmMaximum; 20395f957cafSJames Feist try 20405f957cafSJames Feist { 204115419dd5SVernon Mauery cfmLimit = ipmi::getDbusProperty(*dbus, settingsBusName, 20425f957cafSJames Feist cfmLimitSettingPath, cfmLimitIface, 20435f957cafSJames Feist "Limit"); 20445f957cafSJames Feist cfmMaximum = ipmi::getDbusProperty( 204515419dd5SVernon Mauery *dbus, "xyz.openbmc_project.ExitAirTempSensor", 20465f957cafSJames Feist "/xyz/openbmc_project/control/MaxCFM", cfmLimitIface, "Limit"); 20475f957cafSJames Feist } 20485f957cafSJames Feist catch (sdbusplus::exception_t& e) 20495f957cafSJames Feist { 20505f957cafSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 2051acc8a4ebSJames Feist "ipmiOEMGetFscParameter: can't get cfm setting!", 20525f957cafSJames Feist phosphor::logging::entry("ERR=%s", e.what())); 2053acc8a4ebSJames Feist return ipmi::responseResponseError(); 20545f957cafSJames Feist } 20555f957cafSJames Feist 2056acc8a4ebSJames Feist double cfmMax = std::get<double>(cfmMaximum); 2057acc8a4ebSJames Feist double cfmLim = std::get<double>(cfmLimit); 2058acc8a4ebSJames Feist 2059acc8a4ebSJames Feist cfmLim = std::floor(cfmLim + 0.5); 2060acc8a4ebSJames Feist cfmMax = std::floor(cfmMax + 0.5); 2061acc8a4ebSJames Feist uint16_t cfmLimResp = static_cast<uint16_t>(cfmLim); 2062acc8a4ebSJames Feist uint16_t cfmMaxResp = static_cast<uint16_t>(cfmMax); 2063acc8a4ebSJames Feist 2064acc8a4ebSJames Feist return ipmi::responseSuccess( 2065acc8a4ebSJames Feist std::array<uint16_t, 2>{cfmLimResp, cfmMaxResp}); 20665f957cafSJames Feist } 20675f957cafSJames Feist 20685f957cafSJames Feist else 20695f957cafSJames Feist { 20705f957cafSJames Feist // todo other command parts possibly 20715f957cafSJames Feist // domain pwm limit not implemented 2072acc8a4ebSJames Feist return ipmi::responseParmOutOfRange(); 20735f957cafSJames Feist } 20745f957cafSJames Feist } 20755f957cafSJames Feist 2076773703a5SCheng C Yang using crConfigVariant = 2077773703a5SCheng C Yang std::variant<bool, uint8_t, uint32_t, std::vector<uint8_t>, std::string>; 2078773703a5SCheng C Yang 2079773703a5SCheng C Yang int setCRConfig(ipmi::Context::ptr ctx, const std::string& property, 2080773703a5SCheng C Yang const crConfigVariant& value, 2081773703a5SCheng C Yang std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) 2082773703a5SCheng C Yang { 2083773703a5SCheng C Yang boost::system::error_code ec; 2084773703a5SCheng C Yang ctx->bus->yield_method_call<void>( 2085e45333a8SKuiying Wang ctx->yield, ec, "xyz.openbmc_project.PSURedundancy", 2086773703a5SCheng C Yang "/xyz/openbmc_project/control/power_supply_redundancy", 2087773703a5SCheng C Yang "org.freedesktop.DBus.Properties", "Set", 2088773703a5SCheng C Yang "xyz.openbmc_project.Control.PowerSupplyRedundancy", property, value); 2089773703a5SCheng C Yang if (ec) 2090773703a5SCheng C Yang { 2091773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2092773703a5SCheng C Yang "Failed to set dbus property to cold redundancy"); 2093773703a5SCheng C Yang return -1; 2094773703a5SCheng C Yang } 2095773703a5SCheng C Yang 2096773703a5SCheng C Yang return 0; 2097773703a5SCheng C Yang } 2098773703a5SCheng C Yang 2099e45333a8SKuiying Wang int getCRConfig( 2100e45333a8SKuiying Wang ipmi::Context::ptr ctx, const std::string& property, crConfigVariant& value, 2101e45333a8SKuiying Wang const std::string& service = "xyz.openbmc_project.PSURedundancy", 2102773703a5SCheng C Yang std::chrono::microseconds timeout = ipmi::IPMI_DBUS_TIMEOUT) 2103773703a5SCheng C Yang { 2104773703a5SCheng C Yang boost::system::error_code ec; 2105773703a5SCheng C Yang value = ctx->bus->yield_method_call<crConfigVariant>( 210619445ab7SYong Li ctx->yield, ec, service, 2107773703a5SCheng C Yang "/xyz/openbmc_project/control/power_supply_redundancy", 2108773703a5SCheng C Yang "org.freedesktop.DBus.Properties", "Get", 2109773703a5SCheng C Yang "xyz.openbmc_project.Control.PowerSupplyRedundancy", property); 2110773703a5SCheng C Yang if (ec) 2111773703a5SCheng C Yang { 2112773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2113773703a5SCheng C Yang "Failed to get dbus property to cold redundancy"); 2114773703a5SCheng C Yang return -1; 2115773703a5SCheng C Yang } 2116773703a5SCheng C Yang return 0; 2117773703a5SCheng C Yang } 2118773703a5SCheng C Yang 2119773703a5SCheng C Yang uint8_t getPSUCount(void) 2120773703a5SCheng C Yang { 2121773703a5SCheng C Yang std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2122773703a5SCheng C Yang ipmi::Value num; 2123773703a5SCheng C Yang try 2124773703a5SCheng C Yang { 2125773703a5SCheng C Yang num = ipmi::getDbusProperty( 2126773703a5SCheng C Yang *dbus, "xyz.openbmc_project.PSURedundancy", 2127773703a5SCheng C Yang "/xyz/openbmc_project/control/power_supply_redundancy", 2128773703a5SCheng C Yang "xyz.openbmc_project.Control.PowerSupplyRedundancy", "PSUNumber"); 2129773703a5SCheng C Yang } 2130773703a5SCheng C Yang catch (sdbusplus::exception_t& e) 2131773703a5SCheng C Yang { 2132773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2133773703a5SCheng C Yang "Failed to get PSUNumber property from dbus interface"); 2134773703a5SCheng C Yang return 0; 2135773703a5SCheng C Yang } 2136773703a5SCheng C Yang uint8_t* pNum = std::get_if<uint8_t>(&num); 2137773703a5SCheng C Yang if (!pNum) 2138773703a5SCheng C Yang { 2139773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2140773703a5SCheng C Yang "Error to get PSU Number"); 2141773703a5SCheng C Yang return 0; 2142773703a5SCheng C Yang } 2143773703a5SCheng C Yang return *pNum; 2144773703a5SCheng C Yang } 2145773703a5SCheng C Yang 2146773703a5SCheng C Yang bool validateCRAlgo(std::vector<uint8_t>& conf, uint8_t num) 2147773703a5SCheng C Yang { 2148773703a5SCheng C Yang if (conf.size() < num) 2149773703a5SCheng C Yang { 2150773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2151773703a5SCheng C Yang "Invalid PSU Ranking"); 2152773703a5SCheng C Yang return false; 2153773703a5SCheng C Yang } 2154773703a5SCheng C Yang std::set<uint8_t> confSet; 2155773703a5SCheng C Yang for (uint8_t i = 0; i < num; i++) 2156773703a5SCheng C Yang { 2157773703a5SCheng C Yang if (conf[i] > num) 2158773703a5SCheng C Yang { 2159773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2160773703a5SCheng C Yang "PSU Ranking is larger than current PSU number"); 2161773703a5SCheng C Yang return false; 2162773703a5SCheng C Yang } 2163773703a5SCheng C Yang confSet.emplace(conf[i]); 2164773703a5SCheng C Yang } 2165773703a5SCheng C Yang 2166773703a5SCheng C Yang if (confSet.size() != num) 2167773703a5SCheng C Yang { 2168773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2169773703a5SCheng C Yang "duplicate PSU Ranking"); 2170773703a5SCheng C Yang return false; 2171773703a5SCheng C Yang } 2172773703a5SCheng C Yang return true; 2173773703a5SCheng C Yang } 2174773703a5SCheng C Yang 2175773703a5SCheng C Yang enum class crParameter 2176773703a5SCheng C Yang { 2177773703a5SCheng C Yang crStatus = 0, 2178773703a5SCheng C Yang crFeature = 1, 2179773703a5SCheng C Yang rotationFeature = 2, 2180773703a5SCheng C Yang rotationAlgo = 3, 2181773703a5SCheng C Yang rotationPeriod = 4, 218219445ab7SYong Li numOfPSU = 5, 218319445ab7SYong Li rotationRankOrderEffective = 6 2184773703a5SCheng C Yang }; 2185773703a5SCheng C Yang 2186773703a5SCheng C Yang constexpr ipmi::Cc ccParameterNotSupported = 0x80; 2187773703a5SCheng C Yang static const constexpr uint32_t oneDay = 0x15180; 2188773703a5SCheng C Yang static const constexpr uint32_t oneMonth = 0xf53700; 2189773703a5SCheng C Yang static const constexpr uint8_t userSpecific = 0x01; 2190773703a5SCheng C Yang static const constexpr uint8_t crSetCompleted = 0; 2191773703a5SCheng C Yang ipmi::RspType<uint8_t> ipmiOEMSetCRConfig(ipmi::Context::ptr ctx, 2192773703a5SCheng C Yang uint8_t parameter, 2193773703a5SCheng C Yang ipmi::message::Payload& payload) 2194773703a5SCheng C Yang { 2195773703a5SCheng C Yang switch (static_cast<crParameter>(parameter)) 2196773703a5SCheng C Yang { 2197773703a5SCheng C Yang case crParameter::rotationFeature: 2198773703a5SCheng C Yang { 2199773703a5SCheng C Yang uint8_t param1; 2200773703a5SCheng C Yang if (payload.unpack(param1) || !payload.fullyUnpacked()) 2201773703a5SCheng C Yang { 2202773703a5SCheng C Yang return ipmi::responseReqDataLenInvalid(); 2203773703a5SCheng C Yang } 2204773703a5SCheng C Yang // Rotation Enable can only be true or false 2205773703a5SCheng C Yang if (param1 > 1) 2206773703a5SCheng C Yang { 2207773703a5SCheng C Yang return ipmi::responseInvalidFieldRequest(); 2208773703a5SCheng C Yang } 2209773703a5SCheng C Yang if (setCRConfig(ctx, "RotationEnabled", static_cast<bool>(param1))) 2210773703a5SCheng C Yang { 2211773703a5SCheng C Yang return ipmi::responseResponseError(); 2212773703a5SCheng C Yang } 2213773703a5SCheng C Yang break; 2214773703a5SCheng C Yang } 2215773703a5SCheng C Yang case crParameter::rotationAlgo: 2216773703a5SCheng C Yang { 2217773703a5SCheng C Yang // Rotation Algorithm can only be 0-BMC Specific or 1-User Specific 2218773703a5SCheng C Yang std::string algoName; 2219773703a5SCheng C Yang uint8_t param1; 2220773703a5SCheng C Yang if (payload.unpack(param1)) 2221773703a5SCheng C Yang { 2222773703a5SCheng C Yang return ipmi::responseReqDataLenInvalid(); 2223773703a5SCheng C Yang } 2224773703a5SCheng C Yang switch (param1) 2225773703a5SCheng C Yang { 2226773703a5SCheng C Yang case 0: 2227773703a5SCheng C Yang algoName = "xyz.openbmc_project.Control." 2228773703a5SCheng C Yang "PowerSupplyRedundancy.Algo.bmcSpecific"; 2229773703a5SCheng C Yang break; 2230773703a5SCheng C Yang case 1: 2231773703a5SCheng C Yang algoName = "xyz.openbmc_project.Control." 2232773703a5SCheng C Yang "PowerSupplyRedundancy.Algo.userSpecific"; 2233773703a5SCheng C Yang break; 2234773703a5SCheng C Yang default: 2235773703a5SCheng C Yang return ipmi::responseInvalidFieldRequest(); 2236773703a5SCheng C Yang } 2237773703a5SCheng C Yang if (setCRConfig(ctx, "RotationAlgorithm", algoName)) 2238773703a5SCheng C Yang { 2239773703a5SCheng C Yang return ipmi::responseResponseError(); 2240773703a5SCheng C Yang } 2241773703a5SCheng C Yang 2242773703a5SCheng C Yang uint8_t numberOfPSU = getPSUCount(); 2243773703a5SCheng C Yang if (!numberOfPSU) 2244773703a5SCheng C Yang { 2245773703a5SCheng C Yang return ipmi::responseResponseError(); 2246773703a5SCheng C Yang } 2247773703a5SCheng C Yang std::vector<uint8_t> rankOrder; 2248773703a5SCheng C Yang 2249773703a5SCheng C Yang if (param1 == userSpecific) 2250773703a5SCheng C Yang { 2251773703a5SCheng C Yang if (payload.unpack(rankOrder) || !payload.fullyUnpacked()) 2252773703a5SCheng C Yang { 2253773703a5SCheng C Yang ipmi::responseReqDataLenInvalid(); 2254773703a5SCheng C Yang } 225583315132SYong Li if (rankOrder.size() != numberOfPSU) 2256773703a5SCheng C Yang { 2257773703a5SCheng C Yang return ipmi::responseReqDataLenInvalid(); 2258773703a5SCheng C Yang } 2259773703a5SCheng C Yang 2260773703a5SCheng C Yang if (!validateCRAlgo(rankOrder, numberOfPSU)) 2261773703a5SCheng C Yang { 2262773703a5SCheng C Yang return ipmi::responseInvalidFieldRequest(); 2263773703a5SCheng C Yang } 2264773703a5SCheng C Yang } 2265773703a5SCheng C Yang else 2266773703a5SCheng C Yang { 2267773703a5SCheng C Yang if (rankOrder.size() > 0) 2268773703a5SCheng C Yang { 2269773703a5SCheng C Yang return ipmi::responseReqDataLenInvalid(); 2270773703a5SCheng C Yang } 2271773703a5SCheng C Yang for (uint8_t i = 1; i <= numberOfPSU; i++) 2272773703a5SCheng C Yang { 2273773703a5SCheng C Yang rankOrder.emplace_back(i); 2274773703a5SCheng C Yang } 2275773703a5SCheng C Yang } 2276773703a5SCheng C Yang if (setCRConfig(ctx, "RotationRankOrder", rankOrder)) 2277773703a5SCheng C Yang { 2278773703a5SCheng C Yang return ipmi::responseResponseError(); 2279773703a5SCheng C Yang } 2280773703a5SCheng C Yang break; 2281773703a5SCheng C Yang } 2282773703a5SCheng C Yang case crParameter::rotationPeriod: 2283773703a5SCheng C Yang { 2284773703a5SCheng C Yang // Minimum Rotation period is One day (86400 seconds) and Max 2285773703a5SCheng C Yang // Rotation Period is 6 month (0xf53700 seconds) 2286773703a5SCheng C Yang uint32_t period; 2287773703a5SCheng C Yang if (payload.unpack(period) || !payload.fullyUnpacked()) 2288773703a5SCheng C Yang { 2289773703a5SCheng C Yang return ipmi::responseReqDataLenInvalid(); 2290773703a5SCheng C Yang } 2291773703a5SCheng C Yang if ((period < oneDay) || (period > oneMonth)) 2292773703a5SCheng C Yang { 2293773703a5SCheng C Yang return ipmi::responseInvalidFieldRequest(); 2294773703a5SCheng C Yang } 2295773703a5SCheng C Yang if (setCRConfig(ctx, "PeriodOfRotation", period)) 2296773703a5SCheng C Yang { 2297773703a5SCheng C Yang return ipmi::responseResponseError(); 2298773703a5SCheng C Yang } 2299773703a5SCheng C Yang break; 2300773703a5SCheng C Yang } 2301773703a5SCheng C Yang default: 2302773703a5SCheng C Yang { 2303773703a5SCheng C Yang return ipmi::response(ccParameterNotSupported); 2304773703a5SCheng C Yang } 2305773703a5SCheng C Yang } 2306773703a5SCheng C Yang 2307773703a5SCheng C Yang return ipmi::responseSuccess(crSetCompleted); 2308773703a5SCheng C Yang } 2309773703a5SCheng C Yang 231083315132SYong Li ipmi::RspType<uint8_t, std::variant<uint8_t, uint32_t, std::vector<uint8_t>>> 2311773703a5SCheng C Yang ipmiOEMGetCRConfig(ipmi::Context::ptr ctx, uint8_t parameter) 2312773703a5SCheng C Yang { 2313773703a5SCheng C Yang crConfigVariant value; 2314773703a5SCheng C Yang switch (static_cast<crParameter>(parameter)) 2315773703a5SCheng C Yang { 2316773703a5SCheng C Yang case crParameter::crStatus: 2317773703a5SCheng C Yang { 2318773703a5SCheng C Yang if (getCRConfig(ctx, "ColdRedundancyStatus", value)) 2319773703a5SCheng C Yang { 2320773703a5SCheng C Yang return ipmi::responseResponseError(); 2321773703a5SCheng C Yang } 2322773703a5SCheng C Yang std::string* pStatus = std::get_if<std::string>(&value); 2323773703a5SCheng C Yang if (!pStatus) 2324773703a5SCheng C Yang { 2325773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2326773703a5SCheng C Yang "Error to get ColdRedundancyStatus property"); 2327773703a5SCheng C Yang return ipmi::responseResponseError(); 2328773703a5SCheng C Yang } 2329773703a5SCheng C Yang namespace server = sdbusplus::xyz::openbmc_project::Control::server; 2330773703a5SCheng C Yang auto status = 2331773703a5SCheng C Yang server::PowerSupplyRedundancy::convertStatusFromString( 2332773703a5SCheng C Yang *pStatus); 2333773703a5SCheng C Yang switch (status) 2334773703a5SCheng C Yang { 2335773703a5SCheng C Yang case server::PowerSupplyRedundancy::Status::inProgress: 2336f41e334dSCheng C Yang return ipmi::responseSuccess(parameter, 2337e45333a8SKuiying Wang static_cast<uint8_t>(1)); 2338773703a5SCheng C Yang 2339773703a5SCheng C Yang case server::PowerSupplyRedundancy::Status::completed: 2340f41e334dSCheng C Yang return ipmi::responseSuccess(parameter, 2341e45333a8SKuiying Wang static_cast<uint8_t>(0)); 2342773703a5SCheng C Yang default: 2343773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2344773703a5SCheng C Yang "Error to get valid status"); 2345773703a5SCheng C Yang return ipmi::responseResponseError(); 2346773703a5SCheng C Yang } 2347773703a5SCheng C Yang } 2348773703a5SCheng C Yang case crParameter::crFeature: 2349773703a5SCheng C Yang { 2350e45333a8SKuiying Wang if (getCRConfig(ctx, "PowerSupplyRedundancyEnabled", value)) 2351773703a5SCheng C Yang { 2352773703a5SCheng C Yang return ipmi::responseResponseError(); 2353773703a5SCheng C Yang } 2354773703a5SCheng C Yang bool* pResponse = std::get_if<bool>(&value); 2355773703a5SCheng C Yang if (!pResponse) 2356773703a5SCheng C Yang { 2357773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2358e45333a8SKuiying Wang "Error to get PowerSupplyRedundancyEnabled property"); 2359773703a5SCheng C Yang return ipmi::responseResponseError(); 2360773703a5SCheng C Yang } 2361773703a5SCheng C Yang 2362f41e334dSCheng C Yang return ipmi::responseSuccess(parameter, 2363f41e334dSCheng C Yang static_cast<uint8_t>(*pResponse)); 2364773703a5SCheng C Yang } 2365773703a5SCheng C Yang case crParameter::rotationFeature: 2366773703a5SCheng C Yang { 2367773703a5SCheng C Yang if (getCRConfig(ctx, "RotationEnabled", value)) 2368773703a5SCheng C Yang { 2369773703a5SCheng C Yang return ipmi::responseResponseError(); 2370773703a5SCheng C Yang } 2371773703a5SCheng C Yang bool* pResponse = std::get_if<bool>(&value); 2372773703a5SCheng C Yang if (!pResponse) 2373773703a5SCheng C Yang { 2374773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2375773703a5SCheng C Yang "Error to get RotationEnabled property"); 2376773703a5SCheng C Yang return ipmi::responseResponseError(); 2377773703a5SCheng C Yang } 2378f41e334dSCheng C Yang return ipmi::responseSuccess(parameter, 2379f41e334dSCheng C Yang static_cast<uint8_t>(*pResponse)); 2380773703a5SCheng C Yang } 2381773703a5SCheng C Yang case crParameter::rotationAlgo: 2382773703a5SCheng C Yang { 2383773703a5SCheng C Yang if (getCRConfig(ctx, "RotationAlgorithm", value)) 2384773703a5SCheng C Yang { 2385773703a5SCheng C Yang return ipmi::responseResponseError(); 2386773703a5SCheng C Yang } 2387773703a5SCheng C Yang 2388773703a5SCheng C Yang std::string* pAlgo = std::get_if<std::string>(&value); 2389773703a5SCheng C Yang if (!pAlgo) 2390773703a5SCheng C Yang { 2391773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2392773703a5SCheng C Yang "Error to get RotationAlgorithm property"); 2393773703a5SCheng C Yang return ipmi::responseResponseError(); 2394773703a5SCheng C Yang } 239583315132SYong Li std::vector<uint8_t> response; 2396773703a5SCheng C Yang namespace server = sdbusplus::xyz::openbmc_project::Control::server; 2397773703a5SCheng C Yang auto algo = 2398773703a5SCheng C Yang server::PowerSupplyRedundancy::convertAlgoFromString(*pAlgo); 239983315132SYong Li 2400773703a5SCheng C Yang switch (algo) 2401773703a5SCheng C Yang { 2402773703a5SCheng C Yang case server::PowerSupplyRedundancy::Algo::bmcSpecific: 240383315132SYong Li response.push_back(0); 2404773703a5SCheng C Yang break; 2405773703a5SCheng C Yang case server::PowerSupplyRedundancy::Algo::userSpecific: 240683315132SYong Li response.push_back(1); 2407773703a5SCheng C Yang break; 2408773703a5SCheng C Yang default: 2409773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2410773703a5SCheng C Yang "Error to get valid algo"); 2411773703a5SCheng C Yang return ipmi::responseResponseError(); 2412773703a5SCheng C Yang } 2413773703a5SCheng C Yang 2414773703a5SCheng C Yang if (getCRConfig(ctx, "RotationRankOrder", value)) 2415773703a5SCheng C Yang { 2416773703a5SCheng C Yang return ipmi::responseResponseError(); 2417773703a5SCheng C Yang } 2418773703a5SCheng C Yang std::vector<uint8_t>* pResponse = 2419773703a5SCheng C Yang std::get_if<std::vector<uint8_t>>(&value); 2420773703a5SCheng C Yang if (!pResponse) 2421773703a5SCheng C Yang { 2422773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2423773703a5SCheng C Yang "Error to get RotationRankOrder property"); 2424773703a5SCheng C Yang return ipmi::responseResponseError(); 2425773703a5SCheng C Yang } 242683315132SYong Li 2427773703a5SCheng C Yang std::copy(pResponse->begin(), pResponse->end(), 242883315132SYong Li std::back_inserter(response)); 242983315132SYong Li 2430f41e334dSCheng C Yang return ipmi::responseSuccess(parameter, response); 2431773703a5SCheng C Yang } 2432773703a5SCheng C Yang case crParameter::rotationPeriod: 2433773703a5SCheng C Yang { 2434773703a5SCheng C Yang if (getCRConfig(ctx, "PeriodOfRotation", value)) 2435773703a5SCheng C Yang { 2436773703a5SCheng C Yang return ipmi::responseResponseError(); 2437773703a5SCheng C Yang } 2438773703a5SCheng C Yang uint32_t* pResponse = std::get_if<uint32_t>(&value); 2439773703a5SCheng C Yang if (!pResponse) 2440773703a5SCheng C Yang { 2441773703a5SCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 2442773703a5SCheng C Yang "Error to get RotationAlgorithm property"); 2443773703a5SCheng C Yang return ipmi::responseResponseError(); 2444773703a5SCheng C Yang } 2445f41e334dSCheng C Yang return ipmi::responseSuccess(parameter, *pResponse); 2446773703a5SCheng C Yang } 2447773703a5SCheng C Yang case crParameter::numOfPSU: 2448773703a5SCheng C Yang { 2449773703a5SCheng C Yang uint8_t numberOfPSU = getPSUCount(); 2450773703a5SCheng C Yang if (!numberOfPSU) 2451773703a5SCheng C Yang { 2452773703a5SCheng C Yang return ipmi::responseResponseError(); 2453773703a5SCheng C Yang } 2454f41e334dSCheng C Yang return ipmi::responseSuccess(parameter, numberOfPSU); 2455773703a5SCheng C Yang } 245619445ab7SYong Li case crParameter::rotationRankOrderEffective: 245719445ab7SYong Li { 245819445ab7SYong Li if (getCRConfig(ctx, "RotationRankOrder", value, 245919445ab7SYong Li "xyz.openbmc_project.PSURedundancy")) 246019445ab7SYong Li { 246119445ab7SYong Li return ipmi::responseResponseError(); 246219445ab7SYong Li } 246319445ab7SYong Li std::vector<uint8_t>* pResponse = 246419445ab7SYong Li std::get_if<std::vector<uint8_t>>(&value); 246519445ab7SYong Li if (!pResponse) 246619445ab7SYong Li { 246719445ab7SYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 246819445ab7SYong Li "Error to get effective RotationRankOrder property"); 246919445ab7SYong Li return ipmi::responseResponseError(); 247019445ab7SYong Li } 247119445ab7SYong Li return ipmi::responseSuccess(parameter, *pResponse); 247219445ab7SYong Li } 2473773703a5SCheng C Yang default: 2474773703a5SCheng C Yang { 2475773703a5SCheng C Yang return ipmi::response(ccParameterNotSupported); 2476773703a5SCheng C Yang } 2477773703a5SCheng C Yang } 2478773703a5SCheng C Yang } 2479773703a5SCheng C Yang 2480be560b09SZhu, Yunge ipmi::RspType<> ipmiOEMSetFaultIndication(uint8_t sourceId, uint8_t faultType, 2481be560b09SZhu, Yunge uint8_t faultState, 2482be560b09SZhu, Yunge uint8_t faultGroup, 2483be560b09SZhu, Yunge std::array<uint8_t, 8>& ledStateData) 2484be560b09SZhu, Yunge { 2485be560b09SZhu, Yunge constexpr auto maxFaultType = static_cast<size_t>(RemoteFaultType::max); 2486be560b09SZhu, Yunge static const std::array<std::string, maxFaultType> faultNames = { 2487be560b09SZhu, Yunge "faultFan", "faultTemp", "faultPower", 2488be560b09SZhu, Yunge "faultDriveSlot", "faultSoftware", "faultMemory"}; 2489be560b09SZhu, Yunge 2490be560b09SZhu, Yunge constexpr uint8_t maxFaultSource = 0x4; 2491be560b09SZhu, Yunge constexpr uint8_t skipLEDs = 0xFF; 2492be560b09SZhu, Yunge constexpr uint8_t pinSize = 64; 2493be560b09SZhu, Yunge constexpr uint8_t groupSize = 16; 2494ce4e73fdSZhikui Ren constexpr uint8_t groupNum = 5; // 4 for fault memory, 1 for faultFan 2495be560b09SZhu, Yunge 2496ce4e73fdSZhikui Ren // same pin names need to be defined in dts file 2497ce4e73fdSZhikui Ren static const std::array<std::array<std::string, groupSize>, groupNum> 2498ce4e73fdSZhikui Ren faultLedPinNames = {{ 2499ce4e73fdSZhikui Ren "LED_CPU1_CH1_DIMM1_FAULT", 2500ce4e73fdSZhikui Ren "LED_CPU1_CH1_DIMM2_FAULT", 2501ce4e73fdSZhikui Ren "LED_CPU1_CH2_DIMM1_FAULT", 2502ce4e73fdSZhikui Ren "LED_CPU1_CH2_DIMM2_FAULT", 2503ce4e73fdSZhikui Ren "LED_CPU1_CH3_DIMM1_FAULT", 2504ce4e73fdSZhikui Ren "LED_CPU1_CH3_DIMM2_FAULT", 2505ce4e73fdSZhikui Ren "LED_CPU1_CH4_DIMM1_FAULT", 2506ce4e73fdSZhikui Ren "LED_CPU1_CH4_DIMM2_FAULT", 2507ce4e73fdSZhikui Ren "LED_CPU1_CH5_DIMM1_FAULT", 2508ce4e73fdSZhikui Ren "LED_CPU1_CH5_DIMM2_FAULT", 2509ce4e73fdSZhikui Ren "LED_CPU1_CH6_DIMM1_FAULT", 2510ce4e73fdSZhikui Ren "LED_CPU1_CH6_DIMM2_FAULT", 2511ce4e73fdSZhikui Ren "", 2512ce4e73fdSZhikui Ren "", 2513ce4e73fdSZhikui Ren "", 2514ce4e73fdSZhikui Ren "", // end of group1 2515ce4e73fdSZhikui Ren "LED_CPU2_CH1_DIMM1_FAULT", 2516ce4e73fdSZhikui Ren "LED_CPU2_CH1_DIMM2_FAULT", 2517ce4e73fdSZhikui Ren "LED_CPU2_CH2_DIMM1_FAULT", 2518ce4e73fdSZhikui Ren "LED_CPU2_CH2_DIMM2_FAULT", 2519ce4e73fdSZhikui Ren "LED_CPU2_CH3_DIMM1_FAULT", 2520ce4e73fdSZhikui Ren "LED_CPU2_CH3_DIMM2_FAULT", 2521ce4e73fdSZhikui Ren "LED_CPU2_CH4_DIMM1_FAULT", 2522ce4e73fdSZhikui Ren "LED_CPU2_CH4_DIMM2_FAULT", 2523ce4e73fdSZhikui Ren "LED_CPU2_CH5_DIMM1_FAULT", 2524ce4e73fdSZhikui Ren "LED_CPU2_CH5_DIMM2_FAULT", 2525ce4e73fdSZhikui Ren "LED_CPU2_CH6_DIMM1_FAULT", 2526ce4e73fdSZhikui Ren "LED_CPU2_CH6_DIMM2_FAULT", 2527ce4e73fdSZhikui Ren "", 2528ce4e73fdSZhikui Ren "", 2529ce4e73fdSZhikui Ren "", 2530ce4e73fdSZhikui Ren "", // endof group2 2531ce4e73fdSZhikui Ren "LED_CPU3_CH1_DIMM1_FAULT", 2532ce4e73fdSZhikui Ren "LED_CPU3_CH1_DIMM2_FAULT", 2533ce4e73fdSZhikui Ren "LED_CPU3_CH2_DIMM1_FAULT", 2534ce4e73fdSZhikui Ren "LED_CPU3_CH2_DIMM2_FAULT", 2535ce4e73fdSZhikui Ren "LED_CPU3_CH3_DIMM1_FAULT", 2536ce4e73fdSZhikui Ren "LED_CPU3_CH3_DIMM2_FAULT", 2537ce4e73fdSZhikui Ren "LED_CPU3_CH4_DIMM1_FAULT", 2538ce4e73fdSZhikui Ren "LED_CPU3_CH4_DIMM2_FAULT", 2539ce4e73fdSZhikui Ren "LED_CPU3_CH5_DIMM1_FAULT", 2540ce4e73fdSZhikui Ren "LED_CPU3_CH5_DIMM2_FAULT", 2541ce4e73fdSZhikui Ren "LED_CPU3_CH6_DIMM1_FAULT", 2542ce4e73fdSZhikui Ren "LED_CPU3_CH6_DIMM2_FAULT", 2543ce4e73fdSZhikui Ren "", 2544ce4e73fdSZhikui Ren "", 2545ce4e73fdSZhikui Ren "", 2546ce4e73fdSZhikui Ren "", // end of group3 2547ce4e73fdSZhikui Ren "LED_CPU4_CH1_DIMM1_FAULT", 2548ce4e73fdSZhikui Ren "LED_CPU4_CH1_DIMM2_FAULT", 2549ce4e73fdSZhikui Ren "LED_CPU4_CH2_DIMM1_FAULT", 2550ce4e73fdSZhikui Ren "LED_CPU4_CH2_DIMM2_FAULT", 2551ce4e73fdSZhikui Ren "LED_CPU4_CH3_DIMM1_FAULT", 2552ce4e73fdSZhikui Ren "LED_CPU4_CH3_DIMM2_FAULT", 2553ce4e73fdSZhikui Ren "LED_CPU4_CH4_DIMM1_FAULT", 2554ce4e73fdSZhikui Ren "LED_CPU4_CH4_DIMM2_FAULT", 2555ce4e73fdSZhikui Ren "LED_CPU4_CH5_DIMM1_FAULT", 2556ce4e73fdSZhikui Ren "LED_CPU4_CH5_DIMM2_FAULT", 2557ce4e73fdSZhikui Ren "LED_CPU4_CH6_DIMM1_FAULT", 2558ce4e73fdSZhikui Ren "LED_CPU4_CH6_DIMM2_FAULT", 2559ce4e73fdSZhikui Ren "", 2560ce4e73fdSZhikui Ren "", 2561ce4e73fdSZhikui Ren "", 2562ce4e73fdSZhikui Ren "", // end of group4 2563ce4e73fdSZhikui Ren "LED_FAN1_FAULT", 2564ce4e73fdSZhikui Ren "LED_FAN2_FAULT", 2565ce4e73fdSZhikui Ren "LED_FAN3_FAULT", 2566ce4e73fdSZhikui Ren "LED_FAN4_FAULT", 2567ce4e73fdSZhikui Ren "LED_FAN5_FAULT", 2568ce4e73fdSZhikui Ren "LED_FAN6_FAULT", 2569ce4e73fdSZhikui Ren "LED_FAN7_FAULT", 2570ce4e73fdSZhikui Ren "LED_FAN8_FAULT", 2571ce4e73fdSZhikui Ren "", 2572ce4e73fdSZhikui Ren "", 2573ce4e73fdSZhikui Ren "", 2574ce4e73fdSZhikui Ren "", 2575ce4e73fdSZhikui Ren "", 2576ce4e73fdSZhikui Ren "", 2577ce4e73fdSZhikui Ren "", 2578ce4e73fdSZhikui Ren "" // end of group5 2579ce4e73fdSZhikui Ren }}; 2580be560b09SZhu, Yunge 2581ce4e73fdSZhikui Ren // Validate the source, fault type -- 2582ce4e73fdSZhikui Ren // (Byte 1) sourceId: Unspecified, Hot-Swap Controller 0, Hot-Swap 2583ce4e73fdSZhikui Ren // Controller 1, BIOS (Byte 2) fault type: fan, temperature, power, 2584ce4e73fdSZhikui Ren // driveslot, software, memory (Byte 3) FaultState: OK, Degraded, 2585ce4e73fdSZhikui Ren // Non-Critical, Critical, Non-Recoverable, (Byte 4) is faultGroup, 2586ce4e73fdSZhikui Ren // definition differs based on fault type (Byte 2) 2587ce4e73fdSZhikui Ren // Type Fan=> Group: 0=FanGroupID, FF-not used 2588ce4e73fdSZhikui Ren // Byte 5-11 00h, not used 2589ce4e73fdSZhikui Ren // Byte12 FanLedState [7:0]-Fans 7:0 2590ce4e73fdSZhikui Ren // Type Memory=> Group: 0 = DIMM GroupID, FF-not used 2591ce4e73fdSZhikui Ren // Byte 5:12 - DIMM LED state (64bit field, LS Byte first) 2592ce4e73fdSZhikui Ren // [63:48] = CPU4 channels 7:0, 2 bits per channel 2593ce4e73fdSZhikui Ren // [47:32] = CPU3 channels 7:0, 2 bits per channel 2594ce4e73fdSZhikui Ren // [31:16] = CPU2 channels 7:0, 2 bits per channel 2595ce4e73fdSZhikui Ren // [15:0] = CPU1 channels 7:0, 2 bits per channel 2596ce4e73fdSZhikui Ren // Type Other=> Component Fault LED Group ID, not used set to 0xFF 2597ce4e73fdSZhikui Ren // Byte[5:12]: reserved 0x00h 2598be560b09SZhu, Yunge if ((sourceId >= maxFaultSource) || 2599be560b09SZhu, Yunge (faultType >= static_cast<int8_t>(RemoteFaultType::max)) || 2600be560b09SZhu, Yunge (faultState >= static_cast<int8_t>(RemoteFaultState::maxFaultState)) || 2601be560b09SZhu, Yunge (faultGroup >= static_cast<int8_t>(DimmFaultType::maxFaultGroup))) 2602be560b09SZhu, Yunge { 2603be560b09SZhu, Yunge return ipmi::responseParmOutOfRange(); 2604be560b09SZhu, Yunge } 2605be560b09SZhu, Yunge 2606ce4e73fdSZhikui Ren size_t pinGroupOffset = 0; 2607ce4e73fdSZhikui Ren size_t pinGroupMax = pinSize / groupSize; 2608ce4e73fdSZhikui Ren if (RemoteFaultType::fan == RemoteFaultType(faultType)) 2609be560b09SZhu, Yunge { 2610ce4e73fdSZhikui Ren pinGroupOffset = 4; 2611ce4e73fdSZhikui Ren pinGroupMax = groupNum - pinSize / groupSize; 2612be560b09SZhu, Yunge } 2613be560b09SZhu, Yunge 2614be560b09SZhu, Yunge switch (RemoteFaultType(faultType)) 2615be560b09SZhu, Yunge { 2616be560b09SZhu, Yunge case (RemoteFaultType::fan): 2617be560b09SZhu, Yunge case (RemoteFaultType::memory): 2618be560b09SZhu, Yunge { 2619be560b09SZhu, Yunge if (faultGroup == skipLEDs) 2620be560b09SZhu, Yunge { 2621be560b09SZhu, Yunge return ipmi::responseSuccess(); 2622be560b09SZhu, Yunge } 2623be560b09SZhu, Yunge // calculate led state bit filed count, each byte has 8bits 2624be560b09SZhu, Yunge // the maximum bits will be 8 * 8 bits 2625be560b09SZhu, Yunge constexpr uint8_t size = sizeof(ledStateData) * 8; 2626ce4e73fdSZhikui Ren 2627ce4e73fdSZhikui Ren // assemble ledState 2628ce4e73fdSZhikui Ren uint64_t ledState = 0; 2629ce4e73fdSZhikui Ren bool hasError = false; 2630be560b09SZhu, Yunge for (int i = 0; i < sizeof(ledStateData); i++) 2631be560b09SZhu, Yunge { 2632be560b09SZhu, Yunge ledState = (uint64_t)(ledState << 8); 2633be560b09SZhu, Yunge ledState = (uint64_t)(ledState | (uint64_t)ledStateData[i]); 2634be560b09SZhu, Yunge } 2635be560b09SZhu, Yunge std::bitset<size> ledStateBits(ledState); 2636ce4e73fdSZhikui Ren 2637ce4e73fdSZhikui Ren for (int group = 0; group < pinGroupMax; group++) 2638ce4e73fdSZhikui Ren { 2639ce4e73fdSZhikui Ren for (int i = 0; i < groupSize; i++) 2640ce4e73fdSZhikui Ren { // skip non-existing pins 2641ce4e73fdSZhikui Ren if (0 == faultLedPinNames[group + pinGroupOffset][i].size()) 2642be560b09SZhu, Yunge { 2643be560b09SZhu, Yunge continue; 2644be560b09SZhu, Yunge } 2645be560b09SZhu, Yunge 2646ce4e73fdSZhikui Ren gpiod::line line = gpiod::find_line( 2647ce4e73fdSZhikui Ren faultLedPinNames[group + pinGroupOffset][i]); 2648ce4e73fdSZhikui Ren if (!line) 2649be560b09SZhu, Yunge { 2650be560b09SZhu, Yunge phosphor::logging::log<phosphor::logging::level::ERR>( 2651be560b09SZhu, Yunge "Not Find Led Gpio Device!", 2652ce4e73fdSZhikui Ren phosphor::logging::entry( 2653ce4e73fdSZhikui Ren "DEVICE=%s", 2654ce4e73fdSZhikui Ren faultLedPinNames[group + pinGroupOffset][i] 2655ce4e73fdSZhikui Ren .c_str())); 2656ce4e73fdSZhikui Ren hasError = true; 2657ce4e73fdSZhikui Ren continue; 2658be560b09SZhu, Yunge } 2659ce4e73fdSZhikui Ren 2660ce4e73fdSZhikui Ren bool activeHigh = 2661ce4e73fdSZhikui Ren (line.active_state() == gpiod::line::ACTIVE_HIGH); 2662ce4e73fdSZhikui Ren try 2663ce4e73fdSZhikui Ren { 2664ce4e73fdSZhikui Ren line.request( 2665ce4e73fdSZhikui Ren {"faultLed", gpiod::line_request::DIRECTION_OUTPUT, 2666ce4e73fdSZhikui Ren activeHigh 2667ce4e73fdSZhikui Ren ? 0 2668ce4e73fdSZhikui Ren : gpiod::line_request::FLAG_ACTIVE_LOW}); 2669ce4e73fdSZhikui Ren line.set_value(ledStateBits[i + group * groupSize]); 2670ce4e73fdSZhikui Ren } 2671ce4e73fdSZhikui Ren catch (std::system_error&) 2672ce4e73fdSZhikui Ren { 2673ce4e73fdSZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 2674ce4e73fdSZhikui Ren "Error write Led Gpio Device!", 2675ce4e73fdSZhikui Ren phosphor::logging::entry( 2676ce4e73fdSZhikui Ren "DEVICE=%s", 2677ce4e73fdSZhikui Ren faultLedPinNames[group + pinGroupOffset][i] 2678ce4e73fdSZhikui Ren .c_str())); 2679ce4e73fdSZhikui Ren hasError = true; 2680ce4e73fdSZhikui Ren continue; 2681ce4e73fdSZhikui Ren } 2682ce4e73fdSZhikui Ren } // for int i 2683ce4e73fdSZhikui Ren } 2684ce4e73fdSZhikui Ren if (hasError) 2685ce4e73fdSZhikui Ren { 2686ce4e73fdSZhikui Ren return ipmi::responseResponseError(); 2687be560b09SZhu, Yunge } 2688be560b09SZhu, Yunge break; 2689be560b09SZhu, Yunge } 2690be560b09SZhu, Yunge default: 2691be560b09SZhu, Yunge { 2692be560b09SZhu, Yunge // now only support two fault types 2693be560b09SZhu, Yunge return ipmi::responseParmOutOfRange(); 2694be560b09SZhu, Yunge } 2695ce4e73fdSZhikui Ren } // switch 2696be560b09SZhu, Yunge return ipmi::responseSuccess(); 2697be560b09SZhu, Yunge } 2698be560b09SZhu, Yunge 2699ea537d53SRichard Marian Thomaiyar ipmi::RspType<uint8_t> ipmiOEMReadBoardProductId() 2700ea537d53SRichard Marian Thomaiyar { 2701ea537d53SRichard Marian Thomaiyar uint8_t prodId = 0; 2702ea537d53SRichard Marian Thomaiyar try 2703ea537d53SRichard Marian Thomaiyar { 270415419dd5SVernon Mauery std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 2705ea537d53SRichard Marian Thomaiyar const DbusObjectInfo& object = getDbusObject( 270615419dd5SVernon Mauery *dbus, "xyz.openbmc_project.Inventory.Item.Board", 2707ea537d53SRichard Marian Thomaiyar "/xyz/openbmc_project/inventory/system/board/", "Baseboard"); 2708ea537d53SRichard Marian Thomaiyar const Value& propValue = getDbusProperty( 270915419dd5SVernon Mauery *dbus, object.second, object.first, 27106c57e5caSSuryakanth Sekar "xyz.openbmc_project.Inventory.Item.Board.Motherboard", 27116c57e5caSSuryakanth Sekar "ProductId"); 2712ea537d53SRichard Marian Thomaiyar prodId = static_cast<uint8_t>(std::get<uint64_t>(propValue)); 2713ea537d53SRichard Marian Thomaiyar } 2714ea537d53SRichard Marian Thomaiyar catch (std::exception& e) 2715ea537d53SRichard Marian Thomaiyar { 2716ea537d53SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 2717ea537d53SRichard Marian Thomaiyar "ipmiOEMReadBoardProductId: Product ID read failed!", 2718ea537d53SRichard Marian Thomaiyar phosphor::logging::entry("ERR=%s", e.what())); 2719ea537d53SRichard Marian Thomaiyar } 2720ea537d53SRichard Marian Thomaiyar return ipmi::responseSuccess(prodId); 2721ea537d53SRichard Marian Thomaiyar } 2722ea537d53SRichard Marian Thomaiyar 2723d801e463SRichard Marian Thomaiyar /** @brief implements the get security mode command 2724d801e463SRichard Marian Thomaiyar * @param ctx - ctx pointer 2725d801e463SRichard Marian Thomaiyar * 2726d801e463SRichard Marian Thomaiyar * @returns IPMI completion code with following data 2727d801e463SRichard Marian Thomaiyar * - restriction mode value - As specified in 2728d801e463SRichard Marian Thomaiyar * xyz.openbmc_project.Control.Security.RestrictionMode.interface.yaml 2729d801e463SRichard Marian Thomaiyar * - special mode value - As specified in 2730d801e463SRichard Marian Thomaiyar * xyz.openbmc_project.Control.Security.SpecialMode.interface.yaml 2731d801e463SRichard Marian Thomaiyar */ 2732d801e463SRichard Marian Thomaiyar ipmi::RspType<uint8_t, uint8_t> ipmiGetSecurityMode(ipmi::Context::ptr ctx) 2733d801e463SRichard Marian Thomaiyar { 2734d801e463SRichard Marian Thomaiyar namespace securityNameSpace = 2735d801e463SRichard Marian Thomaiyar sdbusplus::xyz::openbmc_project::Control::Security::server; 2736d801e463SRichard Marian Thomaiyar uint8_t restrictionModeValue = 0; 2737d801e463SRichard Marian Thomaiyar uint8_t specialModeValue = 0; 2738d801e463SRichard Marian Thomaiyar 2739d801e463SRichard Marian Thomaiyar boost::system::error_code ec; 2740d801e463SRichard Marian Thomaiyar auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>( 274128c7290cSJames Feist ctx->yield, ec, restricionModeService, restricionModeBasePath, 2742d801e463SRichard Marian Thomaiyar dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf, 2743d801e463SRichard Marian Thomaiyar restricionModeProperty); 2744d801e463SRichard Marian Thomaiyar if (ec) 2745d801e463SRichard Marian Thomaiyar { 2746d801e463SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 2747d801e463SRichard Marian Thomaiyar "ipmiGetSecurityMode: failed to get RestrictionMode property", 2748d801e463SRichard Marian Thomaiyar phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2749d801e463SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 2750d801e463SRichard Marian Thomaiyar } 2751d801e463SRichard Marian Thomaiyar restrictionModeValue = static_cast<uint8_t>( 2752d801e463SRichard Marian Thomaiyar securityNameSpace::RestrictionMode::convertModesFromString( 2753d801e463SRichard Marian Thomaiyar std::get<std::string>(varRestrMode))); 27548d4f8d73SRichard Marian Thomaiyar auto varSpecialMode = 27558d4f8d73SRichard Marian Thomaiyar ctx->bus->yield_method_call<std::variant<std::string>>( 275628c7290cSJames Feist ctx->yield, ec, specialModeService, specialModeBasePath, 2757d801e463SRichard Marian Thomaiyar dBusPropertyIntf, dBusPropertyGetMethod, specialModeIntf, 2758d801e463SRichard Marian Thomaiyar specialModeProperty); 2759d801e463SRichard Marian Thomaiyar if (ec) 2760d801e463SRichard Marian Thomaiyar { 2761d801e463SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 2762d801e463SRichard Marian Thomaiyar "ipmiGetSecurityMode: failed to get SpecialMode property", 2763d801e463SRichard Marian Thomaiyar phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2764d801e463SRichard Marian Thomaiyar // fall through, let us not worry about SpecialMode property, which is 2765d801e463SRichard Marian Thomaiyar // not required in user scenario 2766d801e463SRichard Marian Thomaiyar } 2767d801e463SRichard Marian Thomaiyar else 2768d801e463SRichard Marian Thomaiyar { 27698d4f8d73SRichard Marian Thomaiyar specialModeValue = static_cast<uint8_t>( 27708d4f8d73SRichard Marian Thomaiyar securityNameSpace::SpecialMode::convertModesFromString( 27718d4f8d73SRichard Marian Thomaiyar std::get<std::string>(varSpecialMode))); 2772d801e463SRichard Marian Thomaiyar } 2773d801e463SRichard Marian Thomaiyar return ipmi::responseSuccess(restrictionModeValue, specialModeValue); 2774d801e463SRichard Marian Thomaiyar } 2775d801e463SRichard Marian Thomaiyar 2776d801e463SRichard Marian Thomaiyar /** @brief implements the set security mode command 2777d801e463SRichard Marian Thomaiyar * Command allows to upgrade the restriction mode and won't allow 2778d801e463SRichard Marian Thomaiyar * to downgrade from system interface 2779d801e463SRichard Marian Thomaiyar * @param ctx - ctx pointer 2780d801e463SRichard Marian Thomaiyar * @param restrictionMode - restriction mode value to be set. 2781d801e463SRichard Marian Thomaiyar * 2782d801e463SRichard Marian Thomaiyar * @returns IPMI completion code 2783d801e463SRichard Marian Thomaiyar */ 2784d801e463SRichard Marian Thomaiyar ipmi::RspType<> ipmiSetSecurityMode(ipmi::Context::ptr ctx, 278510791062SRichard Marian Thomaiyar uint8_t restrictionMode, 278610791062SRichard Marian Thomaiyar std::optional<uint8_t> specialMode) 2787d801e463SRichard Marian Thomaiyar { 278810791062SRichard Marian Thomaiyar #ifndef BMC_VALIDATION_UNSECURE_FEATURE 278910791062SRichard Marian Thomaiyar if (specialMode) 279010791062SRichard Marian Thomaiyar { 279110791062SRichard Marian Thomaiyar return ipmi::responseReqDataLenInvalid(); 279210791062SRichard Marian Thomaiyar } 279310791062SRichard Marian Thomaiyar #endif 2794d801e463SRichard Marian Thomaiyar namespace securityNameSpace = 2795d801e463SRichard Marian Thomaiyar sdbusplus::xyz::openbmc_project::Control::Security::server; 2796d801e463SRichard Marian Thomaiyar 2797d801e463SRichard Marian Thomaiyar ChannelInfo chInfo; 2798d801e463SRichard Marian Thomaiyar if (getChannelInfo(ctx->channel, chInfo) != ccSuccess) 2799d801e463SRichard Marian Thomaiyar { 2800d801e463SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 2801d801e463SRichard Marian Thomaiyar "ipmiSetSecurityMode: Failed to get Channel Info", 2802d801e463SRichard Marian Thomaiyar phosphor::logging::entry("CHANNEL=%d", ctx->channel)); 2803d801e463SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 2804d801e463SRichard Marian Thomaiyar } 2805d801e463SRichard Marian Thomaiyar auto reqMode = 2806d801e463SRichard Marian Thomaiyar static_cast<securityNameSpace::RestrictionMode::Modes>(restrictionMode); 2807d801e463SRichard Marian Thomaiyar 2808d801e463SRichard Marian Thomaiyar if ((reqMode < securityNameSpace::RestrictionMode::Modes::Provisioning) || 2809d801e463SRichard Marian Thomaiyar (reqMode > 2810d801e463SRichard Marian Thomaiyar securityNameSpace::RestrictionMode::Modes::ProvisionedHostDisabled)) 2811d801e463SRichard Marian Thomaiyar { 2812d801e463SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 2813d801e463SRichard Marian Thomaiyar } 2814d801e463SRichard Marian Thomaiyar 2815d801e463SRichard Marian Thomaiyar boost::system::error_code ec; 2816d801e463SRichard Marian Thomaiyar auto varRestrMode = ctx->bus->yield_method_call<std::variant<std::string>>( 281728c7290cSJames Feist ctx->yield, ec, restricionModeService, restricionModeBasePath, 2818d801e463SRichard Marian Thomaiyar dBusPropertyIntf, dBusPropertyGetMethod, restricionModeIntf, 2819d801e463SRichard Marian Thomaiyar restricionModeProperty); 2820d801e463SRichard Marian Thomaiyar if (ec) 2821d801e463SRichard Marian Thomaiyar { 2822d801e463SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 2823d801e463SRichard Marian Thomaiyar "ipmiSetSecurityMode: failed to get RestrictionMode property", 2824d801e463SRichard Marian Thomaiyar phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2825d801e463SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 2826d801e463SRichard Marian Thomaiyar } 2827d801e463SRichard Marian Thomaiyar auto currentRestrictionMode = 2828d801e463SRichard Marian Thomaiyar securityNameSpace::RestrictionMode::convertModesFromString( 2829d801e463SRichard Marian Thomaiyar std::get<std::string>(varRestrMode)); 2830d801e463SRichard Marian Thomaiyar 2831d801e463SRichard Marian Thomaiyar if (chInfo.mediumType != 2832d801e463SRichard Marian Thomaiyar static_cast<uint8_t>(EChannelMediumType::lan8032) && 2833d801e463SRichard Marian Thomaiyar currentRestrictionMode > reqMode) 2834d801e463SRichard Marian Thomaiyar { 2835d801e463SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 2836d801e463SRichard Marian Thomaiyar "ipmiSetSecurityMode - Downgrading security mode not supported " 2837d801e463SRichard Marian Thomaiyar "through system interface", 2838d801e463SRichard Marian Thomaiyar phosphor::logging::entry( 2839d801e463SRichard Marian Thomaiyar "CUR_MODE=%d", static_cast<uint8_t>(currentRestrictionMode)), 2840d801e463SRichard Marian Thomaiyar phosphor::logging::entry("REQ_MODE=%d", restrictionMode)); 2841d801e463SRichard Marian Thomaiyar return ipmi::responseCommandNotAvailable(); 2842d801e463SRichard Marian Thomaiyar } 2843d801e463SRichard Marian Thomaiyar 2844d801e463SRichard Marian Thomaiyar ec.clear(); 2845d801e463SRichard Marian Thomaiyar ctx->bus->yield_method_call<>( 284628c7290cSJames Feist ctx->yield, ec, restricionModeService, restricionModeBasePath, 2847d801e463SRichard Marian Thomaiyar dBusPropertyIntf, dBusPropertySetMethod, restricionModeIntf, 2848d801e463SRichard Marian Thomaiyar restricionModeProperty, 2849d801e463SRichard Marian Thomaiyar static_cast<std::variant<std::string>>( 2850d801e463SRichard Marian Thomaiyar securityNameSpace::convertForMessage(reqMode))); 2851d801e463SRichard Marian Thomaiyar 2852d801e463SRichard Marian Thomaiyar if (ec) 2853d801e463SRichard Marian Thomaiyar { 2854d801e463SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 2855d801e463SRichard Marian Thomaiyar "ipmiSetSecurityMode: failed to set RestrictionMode property", 2856d801e463SRichard Marian Thomaiyar phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 2857d801e463SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 2858d801e463SRichard Marian Thomaiyar } 285910791062SRichard Marian Thomaiyar 286010791062SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE 286110791062SRichard Marian Thomaiyar if (specialMode) 286210791062SRichard Marian Thomaiyar { 2863d77489f1SJayaprakash Mutyala constexpr uint8_t mfgMode = 0x01; 2864d77489f1SJayaprakash Mutyala // Manufacturing mode is reserved. So can't enable this mode. 2865d77489f1SJayaprakash Mutyala if (specialMode.value() == mfgMode) 2866d77489f1SJayaprakash Mutyala { 2867d77489f1SJayaprakash Mutyala phosphor::logging::log<phosphor::logging::level::INFO>( 2868d77489f1SJayaprakash Mutyala "ipmiSetSecurityMode: Can't enable Manufacturing mode"); 2869d77489f1SJayaprakash Mutyala return ipmi::responseInvalidFieldRequest(); 2870d77489f1SJayaprakash Mutyala } 2871d77489f1SJayaprakash Mutyala 287210791062SRichard Marian Thomaiyar ec.clear(); 287310791062SRichard Marian Thomaiyar ctx->bus->yield_method_call<>( 287410791062SRichard Marian Thomaiyar ctx->yield, ec, specialModeService, specialModeBasePath, 287510791062SRichard Marian Thomaiyar dBusPropertyIntf, dBusPropertySetMethod, specialModeIntf, 287610791062SRichard Marian Thomaiyar specialModeProperty, 287710791062SRichard Marian Thomaiyar static_cast<std::variant<std::string>>( 287810791062SRichard Marian Thomaiyar securityNameSpace::convertForMessage( 287910791062SRichard Marian Thomaiyar static_cast<securityNameSpace::SpecialMode::Modes>( 288010791062SRichard Marian Thomaiyar specialMode.value())))); 288110791062SRichard Marian Thomaiyar 288210791062SRichard Marian Thomaiyar if (ec) 288310791062SRichard Marian Thomaiyar { 288410791062SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 288510791062SRichard Marian Thomaiyar "ipmiSetSecurityMode: failed to set SpecialMode property", 288610791062SRichard Marian Thomaiyar phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 288710791062SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 288810791062SRichard Marian Thomaiyar } 288910791062SRichard Marian Thomaiyar } 289010791062SRichard Marian Thomaiyar #endif 2891d801e463SRichard Marian Thomaiyar return ipmi::responseSuccess(); 2892d801e463SRichard Marian Thomaiyar } 2893d801e463SRichard Marian Thomaiyar 28944ac799d7SVernon Mauery ipmi::RspType<uint8_t /* restore status */> 28954ac799d7SVernon Mauery ipmiRestoreConfiguration(const std::array<uint8_t, 3>& clr, uint8_t cmd) 28964ac799d7SVernon Mauery { 28974ac799d7SVernon Mauery static constexpr std::array<uint8_t, 3> expClr = {'C', 'L', 'R'}; 28984ac799d7SVernon Mauery 28994ac799d7SVernon Mauery if (clr != expClr) 29004ac799d7SVernon Mauery { 29014ac799d7SVernon Mauery return ipmi::responseInvalidFieldRequest(); 29024ac799d7SVernon Mauery } 29034ac799d7SVernon Mauery constexpr uint8_t cmdStatus = 0; 29044ac799d7SVernon Mauery constexpr uint8_t cmdDefaultRestore = 0xaa; 29054ac799d7SVernon Mauery constexpr uint8_t cmdFullRestore = 0xbb; 29064ac799d7SVernon Mauery constexpr uint8_t cmdFormat = 0xcc; 29074ac799d7SVernon Mauery 29084ac799d7SVernon Mauery constexpr const char* restoreOpFname = "/tmp/.rwfs/.restore_op"; 29094ac799d7SVernon Mauery 29104ac799d7SVernon Mauery switch (cmd) 29114ac799d7SVernon Mauery { 29124ac799d7SVernon Mauery case cmdStatus: 29134ac799d7SVernon Mauery break; 29144ac799d7SVernon Mauery case cmdDefaultRestore: 29154ac799d7SVernon Mauery case cmdFullRestore: 29164ac799d7SVernon Mauery case cmdFormat: 29174ac799d7SVernon Mauery { 29184ac799d7SVernon Mauery // write file to rwfs root 29194ac799d7SVernon Mauery int value = (cmd - 1) & 0x03; // map aa, bb, cc => 1, 2, 3 29204ac799d7SVernon Mauery std::ofstream restoreFile(restoreOpFname); 29214ac799d7SVernon Mauery if (!restoreFile) 29224ac799d7SVernon Mauery { 29234ac799d7SVernon Mauery return ipmi::responseUnspecifiedError(); 29244ac799d7SVernon Mauery } 29254ac799d7SVernon Mauery restoreFile << value << "\n"; 2926ba1fbc89SArun P. Mohanan 2927ba1fbc89SArun P. Mohanan phosphor::logging::log<phosphor::logging::level::WARNING>( 2928ba1fbc89SArun P. Mohanan "Restore to default will be performed on next BMC boot", 2929ba1fbc89SArun P. Mohanan phosphor::logging::entry("ACTION=0x%0X", cmd)); 2930ba1fbc89SArun P. Mohanan 29314ac799d7SVernon Mauery break; 29324ac799d7SVernon Mauery } 29334ac799d7SVernon Mauery default: 29344ac799d7SVernon Mauery return ipmi::responseInvalidFieldRequest(); 29354ac799d7SVernon Mauery } 29364ac799d7SVernon Mauery 29374ac799d7SVernon Mauery constexpr uint8_t restorePending = 0; 29384ac799d7SVernon Mauery constexpr uint8_t restoreComplete = 1; 29394ac799d7SVernon Mauery 29404ac799d7SVernon Mauery uint8_t restoreStatus = std::filesystem::exists(restoreOpFname) 29414ac799d7SVernon Mauery ? restorePending 29424ac799d7SVernon Mauery : restoreComplete; 29434ac799d7SVernon Mauery return ipmi::responseSuccess(restoreStatus); 29444ac799d7SVernon Mauery } 29454ac799d7SVernon Mauery 294639736d59SChen Yugang ipmi::RspType<uint8_t> ipmiOEMGetNmiSource(void) 294739736d59SChen Yugang { 294839736d59SChen Yugang uint8_t bmcSource; 294997cf96e6SChen Yugang namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server; 295039736d59SChen Yugang 295139736d59SChen Yugang try 295239736d59SChen Yugang { 295339736d59SChen Yugang std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 295439736d59SChen Yugang std::string service = 295539736d59SChen Yugang getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath); 295639736d59SChen Yugang Value variant = 295739736d59SChen Yugang getDbusProperty(*dbus, service, oemNmiSourceObjPath, 295839736d59SChen Yugang oemNmiSourceIntf, oemNmiBmcSourceObjPathProp); 295939736d59SChen Yugang 296039736d59SChen Yugang switch (nmi::NMISource::convertBMCSourceSignalFromString( 296139736d59SChen Yugang std::get<std::string>(variant))) 296239736d59SChen Yugang { 296339736d59SChen Yugang case nmi::NMISource::BMCSourceSignal::None: 296439736d59SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::none); 296539736d59SChen Yugang break; 296697cf96e6SChen Yugang case nmi::NMISource::BMCSourceSignal::FrontPanelButton: 296797cf96e6SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::frontPanelButton); 296839736d59SChen Yugang break; 296997cf96e6SChen Yugang case nmi::NMISource::BMCSourceSignal::Watchdog: 297097cf96e6SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::watchdog); 297139736d59SChen Yugang break; 297239736d59SChen Yugang case nmi::NMISource::BMCSourceSignal::ChassisCmd: 297339736d59SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::chassisCmd); 297439736d59SChen Yugang break; 297539736d59SChen Yugang case nmi::NMISource::BMCSourceSignal::MemoryError: 297639736d59SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::memoryError); 297739736d59SChen Yugang break; 297897cf96e6SChen Yugang case nmi::NMISource::BMCSourceSignal::PciBusError: 297997cf96e6SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::pciBusError); 298039736d59SChen Yugang break; 298197cf96e6SChen Yugang case nmi::NMISource::BMCSourceSignal::PCH: 298297cf96e6SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::pch); 298339736d59SChen Yugang break; 298497cf96e6SChen Yugang case nmi::NMISource::BMCSourceSignal::Chipset: 298597cf96e6SChen Yugang bmcSource = static_cast<uint8_t>(NmiSource::chipset); 298639736d59SChen Yugang break; 298739736d59SChen Yugang default: 298839736d59SChen Yugang phosphor::logging::log<phosphor::logging::level::ERR>( 298939736d59SChen Yugang "NMI source: invalid property!", 299039736d59SChen Yugang phosphor::logging::entry( 299139736d59SChen Yugang "PROP=%s", std::get<std::string>(variant).c_str())); 299239736d59SChen Yugang return ipmi::responseResponseError(); 299339736d59SChen Yugang } 299439736d59SChen Yugang } 299539736d59SChen Yugang catch (sdbusplus::exception::SdBusError& e) 299639736d59SChen Yugang { 299739736d59SChen Yugang phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 299839736d59SChen Yugang return ipmi::responseResponseError(); 299939736d59SChen Yugang } 300039736d59SChen Yugang 300139736d59SChen Yugang return ipmi::responseSuccess(bmcSource); 300239736d59SChen Yugang } 300339736d59SChen Yugang 300439736d59SChen Yugang ipmi::RspType<> ipmiOEMSetNmiSource(uint8_t sourceId) 300539736d59SChen Yugang { 300697cf96e6SChen Yugang namespace nmi = sdbusplus::xyz::openbmc_project::Chassis::Control::server; 300739736d59SChen Yugang 300839736d59SChen Yugang nmi::NMISource::BMCSourceSignal bmcSourceSignal = 300939736d59SChen Yugang nmi::NMISource::BMCSourceSignal::None; 301039736d59SChen Yugang 301139736d59SChen Yugang switch (NmiSource(sourceId)) 301239736d59SChen Yugang { 301339736d59SChen Yugang case NmiSource::none: 301439736d59SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::None; 301539736d59SChen Yugang break; 301697cf96e6SChen Yugang case NmiSource::frontPanelButton: 301797cf96e6SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::FrontPanelButton; 301839736d59SChen Yugang break; 301997cf96e6SChen Yugang case NmiSource::watchdog: 302097cf96e6SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Watchdog; 302139736d59SChen Yugang break; 302239736d59SChen Yugang case NmiSource::chassisCmd: 302339736d59SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::ChassisCmd; 302439736d59SChen Yugang break; 302539736d59SChen Yugang case NmiSource::memoryError: 302639736d59SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::MemoryError; 302739736d59SChen Yugang break; 302897cf96e6SChen Yugang case NmiSource::pciBusError: 302997cf96e6SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PciBusError; 303039736d59SChen Yugang break; 303197cf96e6SChen Yugang case NmiSource::pch: 303297cf96e6SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::PCH; 303339736d59SChen Yugang break; 303497cf96e6SChen Yugang case NmiSource::chipset: 303597cf96e6SChen Yugang bmcSourceSignal = nmi::NMISource::BMCSourceSignal::Chipset; 303639736d59SChen Yugang break; 303739736d59SChen Yugang default: 303839736d59SChen Yugang phosphor::logging::log<phosphor::logging::level::ERR>( 303939736d59SChen Yugang "NMI source: invalid property!"); 304039736d59SChen Yugang return ipmi::responseResponseError(); 304139736d59SChen Yugang } 304239736d59SChen Yugang 304339736d59SChen Yugang try 304439736d59SChen Yugang { 304539736d59SChen Yugang // keep NMI signal source 304639736d59SChen Yugang std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 304739736d59SChen Yugang std::string service = 304839736d59SChen Yugang getService(*dbus, oemNmiSourceIntf, oemNmiSourceObjPath); 304997cf96e6SChen Yugang setDbusProperty(*dbus, service, oemNmiSourceObjPath, oemNmiSourceIntf, 305039736d59SChen Yugang oemNmiBmcSourceObjPathProp, 305197cf96e6SChen Yugang nmi::convertForMessage(bmcSourceSignal)); 305299be6330SChen Yugang // set Enabled property to inform NMI source handling 305399be6330SChen Yugang // to trigger a NMI_OUT BSOD. 305499be6330SChen Yugang // if it's triggered by NMI source property changed, 305599be6330SChen Yugang // NMI_OUT BSOD could be missed if the same source occurs twice in a row 305699be6330SChen Yugang if (bmcSourceSignal != nmi::NMISource::BMCSourceSignal::None) 305799be6330SChen Yugang { 305899be6330SChen Yugang setDbusProperty(*dbus, service, oemNmiSourceObjPath, 305999be6330SChen Yugang oemNmiSourceIntf, oemNmiEnabledObjPathProp, 306099be6330SChen Yugang static_cast<bool>(true)); 306199be6330SChen Yugang } 306239736d59SChen Yugang } 306339736d59SChen Yugang catch (sdbusplus::exception_t& e) 306439736d59SChen Yugang { 306539736d59SChen Yugang phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 306639736d59SChen Yugang return ipmi::responseResponseError(); 306739736d59SChen Yugang } 306839736d59SChen Yugang 306939736d59SChen Yugang return ipmi::responseSuccess(); 307039736d59SChen Yugang } 307139736d59SChen Yugang 307263efafacSJames Feist namespace dimmOffset 307363efafacSJames Feist { 307463efafacSJames Feist constexpr const char* dimmPower = "DimmPower"; 307563efafacSJames Feist constexpr const char* staticCltt = "StaticCltt"; 307663efafacSJames Feist constexpr const char* offsetPath = "/xyz/openbmc_project/Inventory/Item/Dimm"; 307763efafacSJames Feist constexpr const char* offsetInterface = 307863efafacSJames Feist "xyz.openbmc_project.Inventory.Item.Dimm.Offset"; 307963efafacSJames Feist constexpr const char* property = "DimmOffset"; 308063efafacSJames Feist 308163efafacSJames Feist }; // namespace dimmOffset 308263efafacSJames Feist 308363efafacSJames Feist ipmi::RspType<> 308463efafacSJames Feist ipmiOEMSetDimmOffset(uint8_t type, 308563efafacSJames Feist const std::vector<std::tuple<uint8_t, uint8_t>>& data) 308663efafacSJames Feist { 308763efafacSJames Feist if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) && 308863efafacSJames Feist type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 308963efafacSJames Feist { 309063efafacSJames Feist return ipmi::responseInvalidFieldRequest(); 309163efafacSJames Feist } 309263efafacSJames Feist 309363efafacSJames Feist if (data.empty()) 309463efafacSJames Feist { 309563efafacSJames Feist return ipmi::responseInvalidFieldRequest(); 309663efafacSJames Feist } 309763efafacSJames Feist nlohmann::json json; 309863efafacSJames Feist 309963efafacSJames Feist std::ifstream jsonStream(dimmOffsetFile); 310063efafacSJames Feist if (jsonStream.good()) 310163efafacSJames Feist { 310263efafacSJames Feist json = nlohmann::json::parse(jsonStream, nullptr, false); 310363efafacSJames Feist if (json.is_discarded()) 310463efafacSJames Feist { 310563efafacSJames Feist json = nlohmann::json(); 310663efafacSJames Feist } 310763efafacSJames Feist jsonStream.close(); 310863efafacSJames Feist } 310963efafacSJames Feist 311063efafacSJames Feist std::string typeName; 311163efafacSJames Feist if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower)) 311263efafacSJames Feist { 311363efafacSJames Feist typeName = dimmOffset::dimmPower; 311463efafacSJames Feist } 311563efafacSJames Feist else 311663efafacSJames Feist { 311763efafacSJames Feist typeName = dimmOffset::staticCltt; 311863efafacSJames Feist } 311963efafacSJames Feist 312063efafacSJames Feist nlohmann::json& field = json[typeName]; 312163efafacSJames Feist 312263efafacSJames Feist for (const auto& [index, value] : data) 312363efafacSJames Feist { 312463efafacSJames Feist field[index] = value; 312563efafacSJames Feist } 312663efafacSJames Feist 312763efafacSJames Feist for (nlohmann::json& val : field) 312863efafacSJames Feist { 312963efafacSJames Feist if (val == nullptr) 313063efafacSJames Feist { 313163efafacSJames Feist val = static_cast<uint8_t>(0); 313263efafacSJames Feist } 313363efafacSJames Feist } 313463efafacSJames Feist 313563efafacSJames Feist std::ofstream output(dimmOffsetFile); 313663efafacSJames Feist if (!output.good()) 313763efafacSJames Feist { 313863efafacSJames Feist std::cerr << "Error writing json file\n"; 313963efafacSJames Feist return ipmi::responseResponseError(); 314063efafacSJames Feist } 314163efafacSJames Feist 314263efafacSJames Feist output << json.dump(4); 314363efafacSJames Feist 314463efafacSJames Feist if (type == static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 314563efafacSJames Feist { 314663efafacSJames Feist std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus(); 314763efafacSJames Feist 314863efafacSJames Feist std::variant<std::vector<uint8_t>> offsets = 314963efafacSJames Feist field.get<std::vector<uint8_t>>(); 315063efafacSJames Feist auto call = bus->new_method_call( 315163efafacSJames Feist settingsBusName, dimmOffset::offsetPath, PROP_INTF, "Set"); 315263efafacSJames Feist call.append(dimmOffset::offsetInterface, dimmOffset::property, offsets); 315363efafacSJames Feist try 315463efafacSJames Feist { 315563efafacSJames Feist bus->call(call); 315663efafacSJames Feist } 315763efafacSJames Feist catch (sdbusplus::exception_t& e) 315863efafacSJames Feist { 315963efafacSJames Feist phosphor::logging::log<phosphor::logging::level::ERR>( 316063efafacSJames Feist "ipmiOEMSetDimmOffset: can't set dimm offsets!", 316163efafacSJames Feist phosphor::logging::entry("ERR=%s", e.what())); 316263efafacSJames Feist return ipmi::responseResponseError(); 316363efafacSJames Feist } 316463efafacSJames Feist } 316563efafacSJames Feist 316663efafacSJames Feist return ipmi::responseSuccess(); 316763efafacSJames Feist } 316863efafacSJames Feist 316963efafacSJames Feist ipmi::RspType<uint8_t> ipmiOEMGetDimmOffset(uint8_t type, uint8_t index) 317063efafacSJames Feist { 317163efafacSJames Feist 317263efafacSJames Feist if (type != static_cast<uint8_t>(dimmOffsetTypes::dimmPower) && 317363efafacSJames Feist type != static_cast<uint8_t>(dimmOffsetTypes::staticCltt)) 317463efafacSJames Feist { 317563efafacSJames Feist return ipmi::responseInvalidFieldRequest(); 317663efafacSJames Feist } 317763efafacSJames Feist 317863efafacSJames Feist std::ifstream jsonStream(dimmOffsetFile); 317963efafacSJames Feist 318063efafacSJames Feist auto json = nlohmann::json::parse(jsonStream, nullptr, false); 318163efafacSJames Feist if (json.is_discarded()) 318263efafacSJames Feist { 318363efafacSJames Feist std::cerr << "File error in " << dimmOffsetFile << "\n"; 318463efafacSJames Feist return ipmi::responseResponseError(); 318563efafacSJames Feist } 318663efafacSJames Feist 318763efafacSJames Feist std::string typeName; 318863efafacSJames Feist if (type == static_cast<uint8_t>(dimmOffsetTypes::dimmPower)) 318963efafacSJames Feist { 319063efafacSJames Feist typeName = dimmOffset::dimmPower; 319163efafacSJames Feist } 319263efafacSJames Feist else 319363efafacSJames Feist { 319463efafacSJames Feist typeName = dimmOffset::staticCltt; 319563efafacSJames Feist } 319663efafacSJames Feist 319763efafacSJames Feist auto it = json.find(typeName); 319863efafacSJames Feist if (it == json.end()) 319963efafacSJames Feist { 320063efafacSJames Feist return ipmi::responseInvalidFieldRequest(); 320163efafacSJames Feist } 320263efafacSJames Feist 320363efafacSJames Feist if (it->size() <= index) 320463efafacSJames Feist { 320563efafacSJames Feist return ipmi::responseInvalidFieldRequest(); 320663efafacSJames Feist } 320763efafacSJames Feist 320863efafacSJames Feist uint8_t resp = it->at(index).get<uint8_t>(); 320963efafacSJames Feist return ipmi::responseSuccess(resp); 321063efafacSJames Feist } 321163efafacSJames Feist 32124f7e76bbSChen,Yugang namespace boot_options 32134f7e76bbSChen,Yugang { 32144f7e76bbSChen,Yugang 32154f7e76bbSChen,Yugang using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server; 32164f7e76bbSChen,Yugang using IpmiValue = uint8_t; 32174f7e76bbSChen,Yugang constexpr auto ipmiDefault = 0; 32184f7e76bbSChen,Yugang 32194f7e76bbSChen,Yugang std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = { 32204f7e76bbSChen,Yugang {0x01, Source::Sources::Network}, 32214f7e76bbSChen,Yugang {0x02, Source::Sources::Disk}, 32224f7e76bbSChen,Yugang {0x05, Source::Sources::ExternalMedia}, 32234f7e76bbSChen,Yugang {0x0f, Source::Sources::RemovableMedia}, 32244f7e76bbSChen,Yugang {ipmiDefault, Source::Sources::Default}}; 32254f7e76bbSChen,Yugang 32264f7e76bbSChen,Yugang std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = { 3227ca12a7beSChen Yugang {0x06, Mode::Modes::Setup}, {ipmiDefault, Mode::Modes::Regular}}; 32284f7e76bbSChen,Yugang 32294f7e76bbSChen,Yugang std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = { 32304f7e76bbSChen,Yugang {Source::Sources::Network, 0x01}, 32314f7e76bbSChen,Yugang {Source::Sources::Disk, 0x02}, 32324f7e76bbSChen,Yugang {Source::Sources::ExternalMedia, 0x05}, 32334f7e76bbSChen,Yugang {Source::Sources::RemovableMedia, 0x0f}, 32344f7e76bbSChen,Yugang {Source::Sources::Default, ipmiDefault}}; 32354f7e76bbSChen,Yugang 32364f7e76bbSChen,Yugang std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = { 3237ca12a7beSChen Yugang {Mode::Modes::Setup, 0x06}, {Mode::Modes::Regular, ipmiDefault}}; 32384f7e76bbSChen,Yugang 32394f7e76bbSChen,Yugang static constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; 32404f7e76bbSChen,Yugang static constexpr auto bootSourceIntf = 32414f7e76bbSChen,Yugang "xyz.openbmc_project.Control.Boot.Source"; 32424f7e76bbSChen,Yugang static constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable"; 32434f7e76bbSChen,Yugang static constexpr auto persistentObjPath = 32444f7e76bbSChen,Yugang "/xyz/openbmc_project/control/host0/boot"; 32454f7e76bbSChen,Yugang static constexpr auto oneTimePath = 32464f7e76bbSChen,Yugang "/xyz/openbmc_project/control/host0/boot/one_time"; 32474f7e76bbSChen,Yugang static constexpr auto bootSourceProp = "BootSource"; 32484f7e76bbSChen,Yugang static constexpr auto bootModeProp = "BootMode"; 32494f7e76bbSChen,Yugang static constexpr auto oneTimeBootEnableProp = "Enabled"; 32504f7e76bbSChen,Yugang static constexpr auto httpBootMode = 32514f7e76bbSChen,Yugang "xyz.openbmc_project.Control.Boot.Source.Sources.Http"; 32524f7e76bbSChen,Yugang 32534f7e76bbSChen,Yugang enum class BootOptionParameter : size_t 32544f7e76bbSChen,Yugang { 32554f7e76bbSChen,Yugang setInProgress = 0x0, 32564f7e76bbSChen,Yugang bootFlags = 0x5, 32574f7e76bbSChen,Yugang }; 32584f7e76bbSChen,Yugang static constexpr uint8_t setComplete = 0x0; 32594f7e76bbSChen,Yugang static constexpr uint8_t setInProgress = 0x1; 32604f7e76bbSChen,Yugang static uint8_t transferStatus = setComplete; 32614f7e76bbSChen,Yugang static constexpr uint8_t setParmVersion = 0x01; 32624f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsPermanent = 0x40; 32634f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsValidOneTime = 0x80; 32644f7e76bbSChen,Yugang static constexpr uint8_t setParmBootFlagsValidPermanent = 0xC0; 32654f7e76bbSChen,Yugang static constexpr uint8_t httpBoot = 0xd; 32664f7e76bbSChen,Yugang static constexpr uint8_t bootSourceMask = 0x3c; 32674f7e76bbSChen,Yugang 32684f7e76bbSChen,Yugang } // namespace boot_options 32694f7e76bbSChen,Yugang 32704f7e76bbSChen,Yugang ipmi::RspType<uint8_t, // version 32714f7e76bbSChen,Yugang uint8_t, // param 32724f7e76bbSChen,Yugang uint8_t, // data0, dependent on parameter 32734f7e76bbSChen,Yugang std::optional<uint8_t> // data1, dependent on parameter 32744f7e76bbSChen,Yugang > 32754f7e76bbSChen,Yugang ipmiOemGetEfiBootOptions(uint8_t parameter, uint8_t set, uint8_t block) 32764f7e76bbSChen,Yugang { 32774f7e76bbSChen,Yugang using namespace boot_options; 32784f7e76bbSChen,Yugang uint8_t bootOption = 0; 32794f7e76bbSChen,Yugang 32804f7e76bbSChen,Yugang if (parameter == static_cast<uint8_t>(BootOptionParameter::setInProgress)) 32814f7e76bbSChen,Yugang { 32824f7e76bbSChen,Yugang return ipmi::responseSuccess(setParmVersion, parameter, transferStatus, 32834f7e76bbSChen,Yugang std::nullopt); 32844f7e76bbSChen,Yugang } 32854f7e76bbSChen,Yugang 32864f7e76bbSChen,Yugang if (parameter != static_cast<uint8_t>(BootOptionParameter::bootFlags)) 32874f7e76bbSChen,Yugang { 32884f7e76bbSChen,Yugang phosphor::logging::log<phosphor::logging::level::ERR>( 32894f7e76bbSChen,Yugang "Unsupported parameter"); 32904f7e76bbSChen,Yugang return ipmi::responseResponseError(); 32914f7e76bbSChen,Yugang } 32924f7e76bbSChen,Yugang 32934f7e76bbSChen,Yugang try 32944f7e76bbSChen,Yugang { 32954f7e76bbSChen,Yugang auto oneTimeEnabled = false; 32964f7e76bbSChen,Yugang // read one time Enabled property 32974f7e76bbSChen,Yugang std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 32984f7e76bbSChen,Yugang std::string service = getService(*dbus, enabledIntf, oneTimePath); 32994f7e76bbSChen,Yugang Value variant = getDbusProperty(*dbus, service, oneTimePath, 33004f7e76bbSChen,Yugang enabledIntf, oneTimeBootEnableProp); 33014f7e76bbSChen,Yugang oneTimeEnabled = std::get<bool>(variant); 33024f7e76bbSChen,Yugang 33034f7e76bbSChen,Yugang // get BootSource and BootMode properties 33044f7e76bbSChen,Yugang // according to oneTimeEnable 33054f7e76bbSChen,Yugang auto bootObjPath = oneTimePath; 33064f7e76bbSChen,Yugang if (oneTimeEnabled == false) 33074f7e76bbSChen,Yugang { 33084f7e76bbSChen,Yugang bootObjPath = persistentObjPath; 33094f7e76bbSChen,Yugang } 33104f7e76bbSChen,Yugang 33114f7e76bbSChen,Yugang service = getService(*dbus, bootModeIntf, bootObjPath); 33124f7e76bbSChen,Yugang variant = getDbusProperty(*dbus, service, bootObjPath, bootModeIntf, 33134f7e76bbSChen,Yugang bootModeProp); 33144f7e76bbSChen,Yugang 33154f7e76bbSChen,Yugang auto bootMode = 33164f7e76bbSChen,Yugang Mode::convertModesFromString(std::get<std::string>(variant)); 33174f7e76bbSChen,Yugang 33184f7e76bbSChen,Yugang service = getService(*dbus, bootSourceIntf, bootObjPath); 33194f7e76bbSChen,Yugang variant = getDbusProperty(*dbus, service, bootObjPath, bootSourceIntf, 33204f7e76bbSChen,Yugang bootSourceProp); 33214f7e76bbSChen,Yugang 33224f7e76bbSChen,Yugang if (std::get<std::string>(variant) == httpBootMode) 33234f7e76bbSChen,Yugang { 33244f7e76bbSChen,Yugang bootOption = httpBoot; 33254f7e76bbSChen,Yugang } 33264f7e76bbSChen,Yugang else 33274f7e76bbSChen,Yugang { 33284f7e76bbSChen,Yugang auto bootSource = Source::convertSourcesFromString( 33294f7e76bbSChen,Yugang std::get<std::string>(variant)); 33304f7e76bbSChen,Yugang bootOption = sourceDbusToIpmi.at(bootSource); 33314f7e76bbSChen,Yugang if (Source::Sources::Default == bootSource) 33324f7e76bbSChen,Yugang { 33334f7e76bbSChen,Yugang bootOption = modeDbusToIpmi.at(bootMode); 33344f7e76bbSChen,Yugang } 33354f7e76bbSChen,Yugang } 33364f7e76bbSChen,Yugang 33374f7e76bbSChen,Yugang uint8_t oneTime = oneTimeEnabled ? setParmBootFlagsValidOneTime 33384f7e76bbSChen,Yugang : setParmBootFlagsValidPermanent; 33394f7e76bbSChen,Yugang bootOption <<= 2; // shift for responseconstexpr 33404f7e76bbSChen,Yugang return ipmi::responseSuccess(setParmVersion, parameter, oneTime, 33414f7e76bbSChen,Yugang bootOption); 33424f7e76bbSChen,Yugang } 33434f7e76bbSChen,Yugang catch (sdbusplus::exception_t& e) 33444f7e76bbSChen,Yugang { 33454f7e76bbSChen,Yugang phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 33464f7e76bbSChen,Yugang return ipmi::responseResponseError(); 33474f7e76bbSChen,Yugang } 33484f7e76bbSChen,Yugang } 33494f7e76bbSChen,Yugang 33504f7e76bbSChen,Yugang ipmi::RspType<> ipmiOemSetEfiBootOptions(uint8_t bootFlag, uint8_t bootParam, 33514f7e76bbSChen,Yugang std::optional<uint8_t> bootOption) 33524f7e76bbSChen,Yugang { 33534f7e76bbSChen,Yugang using namespace boot_options; 33544f7e76bbSChen,Yugang auto oneTimeEnabled = false; 33554f7e76bbSChen,Yugang 33564f7e76bbSChen,Yugang if (bootFlag == static_cast<uint8_t>(BootOptionParameter::setInProgress)) 33574f7e76bbSChen,Yugang { 33584f7e76bbSChen,Yugang if (bootOption) 33594f7e76bbSChen,Yugang { 33604f7e76bbSChen,Yugang return ipmi::responseReqDataLenInvalid(); 33614f7e76bbSChen,Yugang } 33624f7e76bbSChen,Yugang 33634f7e76bbSChen,Yugang if (transferStatus == setInProgress) 33644f7e76bbSChen,Yugang { 33654f7e76bbSChen,Yugang phosphor::logging::log<phosphor::logging::level::ERR>( 33664f7e76bbSChen,Yugang "boot option set in progress!"); 33674f7e76bbSChen,Yugang return ipmi::responseResponseError(); 33684f7e76bbSChen,Yugang } 33694f7e76bbSChen,Yugang 33704f7e76bbSChen,Yugang transferStatus = bootParam; 33714f7e76bbSChen,Yugang return ipmi::responseSuccess(); 33724f7e76bbSChen,Yugang } 33734f7e76bbSChen,Yugang 33744f7e76bbSChen,Yugang if (bootFlag != (uint8_t)BootOptionParameter::bootFlags) 33754f7e76bbSChen,Yugang { 33764f7e76bbSChen,Yugang phosphor::logging::log<phosphor::logging::level::ERR>( 33774f7e76bbSChen,Yugang "Unsupported parameter"); 33784f7e76bbSChen,Yugang return ipmi::responseResponseError(); 33794f7e76bbSChen,Yugang } 33804f7e76bbSChen,Yugang 33814f7e76bbSChen,Yugang if (!bootOption) 33824f7e76bbSChen,Yugang { 33834f7e76bbSChen,Yugang return ipmi::responseReqDataLenInvalid(); 33844f7e76bbSChen,Yugang } 33854f7e76bbSChen,Yugang 33864f7e76bbSChen,Yugang if (((bootOption.value() & bootSourceMask) >> 2) != 33874f7e76bbSChen,Yugang httpBoot) // not http boot, exit 33884f7e76bbSChen,Yugang { 33894f7e76bbSChen,Yugang phosphor::logging::log<phosphor::logging::level::ERR>( 33904f7e76bbSChen,Yugang "wrong boot option parameter!"); 33914f7e76bbSChen,Yugang return ipmi::responseParmOutOfRange(); 33924f7e76bbSChen,Yugang } 33934f7e76bbSChen,Yugang 33944f7e76bbSChen,Yugang try 33954f7e76bbSChen,Yugang { 33964f7e76bbSChen,Yugang bool permanent = (bootParam & setParmBootFlagsPermanent) == 33974f7e76bbSChen,Yugang setParmBootFlagsPermanent; 33984f7e76bbSChen,Yugang 33994f7e76bbSChen,Yugang // read one time Enabled property 34004f7e76bbSChen,Yugang std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus(); 34014f7e76bbSChen,Yugang std::string service = getService(*dbus, enabledIntf, oneTimePath); 34024f7e76bbSChen,Yugang Value variant = getDbusProperty(*dbus, service, oneTimePath, 34034f7e76bbSChen,Yugang enabledIntf, oneTimeBootEnableProp); 34044f7e76bbSChen,Yugang oneTimeEnabled = std::get<bool>(variant); 34054f7e76bbSChen,Yugang 34064f7e76bbSChen,Yugang /* 34074f7e76bbSChen,Yugang * Check if the current boot setting is onetime or permanent, if the 34084f7e76bbSChen,Yugang * request in the command is otherwise, then set the "Enabled" 34094f7e76bbSChen,Yugang * property in one_time object path to 'True' to indicate onetime 34104f7e76bbSChen,Yugang * and 'False' to indicate permanent. 34114f7e76bbSChen,Yugang * 34124f7e76bbSChen,Yugang * Once the onetime/permanent setting is applied, then the bootMode 34134f7e76bbSChen,Yugang * and bootSource is updated for the corresponding object. 34144f7e76bbSChen,Yugang */ 34154f7e76bbSChen,Yugang if (permanent == oneTimeEnabled) 34164f7e76bbSChen,Yugang { 34174f7e76bbSChen,Yugang setDbusProperty(*dbus, service, oneTimePath, enabledIntf, 34184f7e76bbSChen,Yugang oneTimeBootEnableProp, !permanent); 34194f7e76bbSChen,Yugang } 34204f7e76bbSChen,Yugang 34214f7e76bbSChen,Yugang // set BootSource and BootMode properties 34224f7e76bbSChen,Yugang // according to oneTimeEnable or persistent 34234f7e76bbSChen,Yugang auto bootObjPath = oneTimePath; 34244f7e76bbSChen,Yugang if (oneTimeEnabled == false) 34254f7e76bbSChen,Yugang { 34264f7e76bbSChen,Yugang bootObjPath = persistentObjPath; 34274f7e76bbSChen,Yugang } 34284f7e76bbSChen,Yugang std::string bootMode = 34294f7e76bbSChen,Yugang "xyz.openbmc_project.Control.Boot.Mode.Modes.Regular"; 34304f7e76bbSChen,Yugang std::string bootSource = httpBootMode; 34314f7e76bbSChen,Yugang 34324f7e76bbSChen,Yugang service = getService(*dbus, bootModeIntf, bootObjPath); 34334f7e76bbSChen,Yugang setDbusProperty(*dbus, service, bootObjPath, bootModeIntf, bootModeProp, 34344f7e76bbSChen,Yugang bootMode); 34354f7e76bbSChen,Yugang 34364f7e76bbSChen,Yugang service = getService(*dbus, bootSourceIntf, bootObjPath); 34374f7e76bbSChen,Yugang setDbusProperty(*dbus, service, bootObjPath, bootSourceIntf, 34384f7e76bbSChen,Yugang bootSourceProp, bootSource); 34394f7e76bbSChen,Yugang } 34404f7e76bbSChen,Yugang catch (sdbusplus::exception_t& e) 34414f7e76bbSChen,Yugang { 34424f7e76bbSChen,Yugang phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 34434f7e76bbSChen,Yugang return ipmi::responseResponseError(); 34444f7e76bbSChen,Yugang } 34454f7e76bbSChen,Yugang 34464f7e76bbSChen,Yugang return ipmi::responseSuccess(); 34474f7e76bbSChen,Yugang } 34484f7e76bbSChen,Yugang 34494e6ee15bSCheng C Yang using BasicVariantType = 34504e6ee15bSCheng C Yang std::variant<std::vector<std::string>, std::vector<uint64_t>, std::string, 34514e6ee15bSCheng C Yang int64_t, uint64_t, double, int32_t, uint32_t, int16_t, 34524e6ee15bSCheng C Yang uint16_t, uint8_t, bool>; 34534e6ee15bSCheng C Yang using PropertyMapType = 34544e6ee15bSCheng C Yang boost::container::flat_map<std::string, BasicVariantType>; 34554e6ee15bSCheng C Yang static constexpr const std::array<const char*, 1> psuPresenceTypes = { 34564e6ee15bSCheng C Yang "xyz.openbmc_project.Configuration.PSUPresence"}; 34574e6ee15bSCheng C Yang int getPSUAddress(ipmi::Context::ptr ctx, uint8_t& bus, 34584e6ee15bSCheng C Yang std::vector<uint64_t>& addrTable) 34594e6ee15bSCheng C Yang { 34604e6ee15bSCheng C Yang boost::system::error_code ec; 34614e6ee15bSCheng C Yang GetSubTreeType subtree = ctx->bus->yield_method_call<GetSubTreeType>( 34624e6ee15bSCheng C Yang ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 34634e6ee15bSCheng C Yang "/xyz/openbmc_project/object_mapper", 34644e6ee15bSCheng C Yang "xyz.openbmc_project.ObjectMapper", "GetSubTree", 34654e6ee15bSCheng C Yang "/xyz/openbmc_project/inventory/system", 3, psuPresenceTypes); 34664e6ee15bSCheng C Yang if (ec) 34674e6ee15bSCheng C Yang { 34684e6ee15bSCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 34694e6ee15bSCheng C Yang "Failed to set dbus property to cold redundancy"); 34704e6ee15bSCheng C Yang return -1; 34714e6ee15bSCheng C Yang } 34724e6ee15bSCheng C Yang for (const auto& object : subtree) 34734e6ee15bSCheng C Yang { 34744e6ee15bSCheng C Yang std::string pathName = object.first; 34754e6ee15bSCheng C Yang for (const auto& serviceIface : object.second) 34764e6ee15bSCheng C Yang { 34774e6ee15bSCheng C Yang std::string serviceName = serviceIface.first; 34784e6ee15bSCheng C Yang 34794e6ee15bSCheng C Yang ec.clear(); 34804e6ee15bSCheng C Yang PropertyMapType propMap = 34814e6ee15bSCheng C Yang ctx->bus->yield_method_call<PropertyMapType>( 34824e6ee15bSCheng C Yang ctx->yield, ec, serviceName, pathName, 34834e6ee15bSCheng C Yang "org.freedesktop.DBus.Properties", "GetAll", 34844e6ee15bSCheng C Yang "xyz.openbmc_project.Configuration.PSUPresence"); 34854e6ee15bSCheng C Yang if (ec) 34864e6ee15bSCheng C Yang { 34874e6ee15bSCheng C Yang phosphor::logging::log<phosphor::logging::level::ERR>( 34884e6ee15bSCheng C Yang "Failed to set dbus property to cold redundancy"); 34894e6ee15bSCheng C Yang return -1; 34904e6ee15bSCheng C Yang } 34914e6ee15bSCheng C Yang auto psuBus = std::get_if<uint64_t>(&propMap["Bus"]); 34924e6ee15bSCheng C Yang auto psuAddress = 34934e6ee15bSCheng C Yang std::get_if<std::vector<uint64_t>>(&propMap["Address"]); 34944e6ee15bSCheng C Yang 34954e6ee15bSCheng C Yang if (psuBus == nullptr || psuAddress == nullptr) 34964e6ee15bSCheng C Yang { 34974e6ee15bSCheng C Yang std::cerr << "error finding necessary " 34984e6ee15bSCheng C Yang "entry in configuration\n"; 34994e6ee15bSCheng C Yang return -1; 35004e6ee15bSCheng C Yang } 35014e6ee15bSCheng C Yang bus = static_cast<uint8_t>(*psuBus); 35024e6ee15bSCheng C Yang addrTable = *psuAddress; 35034e6ee15bSCheng C Yang return 0; 35044e6ee15bSCheng C Yang } 35054e6ee15bSCheng C Yang } 35064e6ee15bSCheng C Yang return -1; 35074e6ee15bSCheng C Yang } 35084e6ee15bSCheng C Yang 35094e6ee15bSCheng C Yang static const constexpr uint8_t addrOffset = 8; 35104e6ee15bSCheng C Yang static const constexpr uint8_t psuRevision = 0xd9; 35114e6ee15bSCheng C Yang static const constexpr uint8_t defaultPSUBus = 7; 35124e6ee15bSCheng C Yang // Second Minor, Primary Minor, Major 35134e6ee15bSCheng C Yang static const constexpr size_t verLen = 3; 35144e6ee15bSCheng C Yang ipmi::RspType<std::vector<uint8_t>> ipmiOEMGetPSUVersion(ipmi::Context::ptr ctx) 35154e6ee15bSCheng C Yang { 35164e6ee15bSCheng C Yang uint8_t bus = defaultPSUBus; 35174e6ee15bSCheng C Yang std::vector<uint64_t> addrTable; 35184e6ee15bSCheng C Yang std::vector<uint8_t> result; 35194e6ee15bSCheng C Yang if (getPSUAddress(ctx, bus, addrTable)) 35204e6ee15bSCheng C Yang { 35214e6ee15bSCheng C Yang std::cerr << "Failed to get PSU bus and address\n"; 35224e6ee15bSCheng C Yang return ipmi::responseResponseError(); 35234e6ee15bSCheng C Yang } 35244e6ee15bSCheng C Yang 35254e6ee15bSCheng C Yang for (const auto& slaveAddr : addrTable) 35264e6ee15bSCheng C Yang { 35274e6ee15bSCheng C Yang std::vector<uint8_t> writeData = {psuRevision}; 35284e6ee15bSCheng C Yang std::vector<uint8_t> readBuf(verLen); 35294e6ee15bSCheng C Yang uint8_t addr = static_cast<uint8_t>(slaveAddr) + addrOffset; 35304e6ee15bSCheng C Yang std::string i2cBus = "/dev/i2c-" + std::to_string(bus); 35314e6ee15bSCheng C Yang 35324e6ee15bSCheng C Yang auto retI2C = ipmi::i2cWriteRead(i2cBus, addr, writeData, readBuf); 35334e6ee15bSCheng C Yang if (retI2C != ipmi::ccSuccess) 35344e6ee15bSCheng C Yang { 35354e6ee15bSCheng C Yang for (size_t idx = 0; idx < verLen; idx++) 35364e6ee15bSCheng C Yang { 35374e6ee15bSCheng C Yang result.emplace_back(0x00); 35384e6ee15bSCheng C Yang } 35394e6ee15bSCheng C Yang } 35404e6ee15bSCheng C Yang else 35414e6ee15bSCheng C Yang { 35424e6ee15bSCheng C Yang for (const uint8_t& data : readBuf) 35434e6ee15bSCheng C Yang { 35444e6ee15bSCheng C Yang result.emplace_back(data); 35454e6ee15bSCheng C Yang } 35464e6ee15bSCheng C Yang } 35474e6ee15bSCheng C Yang } 35484e6ee15bSCheng C Yang 35494e6ee15bSCheng C Yang return ipmi::responseSuccess(result); 35504e6ee15bSCheng C Yang } 35514e6ee15bSCheng C Yang 35522030d7c8Ssrikanta mondal std::optional<uint8_t> getMultiNodeInfoPresence(ipmi::Context::ptr ctx, 35532030d7c8Ssrikanta mondal const std::string& name) 35542030d7c8Ssrikanta mondal { 35552030d7c8Ssrikanta mondal Value dbusValue = 0; 35562030d7c8Ssrikanta mondal std::string serviceName; 35572030d7c8Ssrikanta mondal 35582030d7c8Ssrikanta mondal boost::system::error_code ec = 35592030d7c8Ssrikanta mondal ipmi::getService(ctx, multiNodeIntf, multiNodeObjPath, serviceName); 35602030d7c8Ssrikanta mondal 35612030d7c8Ssrikanta mondal if (ec) 35622030d7c8Ssrikanta mondal { 35632030d7c8Ssrikanta mondal phosphor::logging::log<phosphor::logging::level::ERR>( 35642030d7c8Ssrikanta mondal "Failed to perform Multinode getService."); 35652030d7c8Ssrikanta mondal return std::nullopt; 35662030d7c8Ssrikanta mondal } 35672030d7c8Ssrikanta mondal 35682030d7c8Ssrikanta mondal ec = ipmi::getDbusProperty(ctx, serviceName, multiNodeObjPath, 35692030d7c8Ssrikanta mondal multiNodeIntf, name, dbusValue); 35702030d7c8Ssrikanta mondal if (ec) 35712030d7c8Ssrikanta mondal { 35722030d7c8Ssrikanta mondal phosphor::logging::log<phosphor::logging::level::ERR>( 35732030d7c8Ssrikanta mondal "Failed to perform Multinode get property"); 35742030d7c8Ssrikanta mondal return std::nullopt; 35752030d7c8Ssrikanta mondal } 35762030d7c8Ssrikanta mondal 35772030d7c8Ssrikanta mondal auto multiNodeVal = std::get_if<uint8_t>(&dbusValue); 35782030d7c8Ssrikanta mondal if (!multiNodeVal) 35792030d7c8Ssrikanta mondal { 35802030d7c8Ssrikanta mondal phosphor::logging::log<phosphor::logging::level::ERR>( 35812030d7c8Ssrikanta mondal "getMultiNodeInfoPresence: error to get multinode"); 35822030d7c8Ssrikanta mondal return std::nullopt; 35832030d7c8Ssrikanta mondal } 35842030d7c8Ssrikanta mondal return *multiNodeVal; 35852030d7c8Ssrikanta mondal } 35862030d7c8Ssrikanta mondal 35872030d7c8Ssrikanta mondal /** @brief implements OEM get reading command 35882030d7c8Ssrikanta mondal * @param domain ID 35892030d7c8Ssrikanta mondal * @param reading Type 35902030d7c8Ssrikanta mondal * - 00h = platform Power Consumption 35912030d7c8Ssrikanta mondal * - 01h = inlet Air Temp 35922030d7c8Ssrikanta mondal * - 02h = icc_TDC from PECI 35932030d7c8Ssrikanta mondal * @param reserved, write as 0000h 35942030d7c8Ssrikanta mondal * 35952030d7c8Ssrikanta mondal * @returns IPMI completion code plus response data 35962030d7c8Ssrikanta mondal * - response 35972030d7c8Ssrikanta mondal * - domain ID 35982030d7c8Ssrikanta mondal * - reading Type 35992030d7c8Ssrikanta mondal * - 00h = platform Power Consumption 36002030d7c8Ssrikanta mondal * - 01h = inlet Air Temp 36012030d7c8Ssrikanta mondal * - 02h = icc_TDC from PECI 36022030d7c8Ssrikanta mondal * - reading 36032030d7c8Ssrikanta mondal */ 36042030d7c8Ssrikanta mondal ipmi::RspType<uint4_t, // domain ID 36052030d7c8Ssrikanta mondal uint4_t, // reading Type 36062030d7c8Ssrikanta mondal uint16_t // reading Value 36072030d7c8Ssrikanta mondal > 36082030d7c8Ssrikanta mondal ipmiOEMGetReading(ipmi::Context::ptr ctx, uint4_t domainId, 36092030d7c8Ssrikanta mondal uint4_t readingType, uint16_t reserved) 36102030d7c8Ssrikanta mondal { 36112030d7c8Ssrikanta mondal constexpr uint8_t platformPower = 0; 36122030d7c8Ssrikanta mondal constexpr uint8_t inletAirTemp = 1; 36132030d7c8Ssrikanta mondal constexpr uint8_t iccTdc = 2; 36142030d7c8Ssrikanta mondal 36152030d7c8Ssrikanta mondal if ((static_cast<uint8_t>(readingType) > iccTdc) || domainId || reserved) 36162030d7c8Ssrikanta mondal { 36172030d7c8Ssrikanta mondal return ipmi::responseInvalidFieldRequest(); 36182030d7c8Ssrikanta mondal } 36192030d7c8Ssrikanta mondal 36202030d7c8Ssrikanta mondal // This command should run only from multi-node product. 36212030d7c8Ssrikanta mondal // For all other platforms this command will return invalid. 36222030d7c8Ssrikanta mondal 36232030d7c8Ssrikanta mondal std::optional<uint8_t> nodeInfo = 36242030d7c8Ssrikanta mondal getMultiNodeInfoPresence(ctx, "NodePresence"); 36252030d7c8Ssrikanta mondal if (!nodeInfo || !*nodeInfo) 36262030d7c8Ssrikanta mondal { 36272030d7c8Ssrikanta mondal return ipmi::responseInvalidCommand(); 36282030d7c8Ssrikanta mondal } 36292030d7c8Ssrikanta mondal 36302030d7c8Ssrikanta mondal uint16_t oemReadingValue = 0; 36312030d7c8Ssrikanta mondal if (static_cast<uint8_t>(readingType) == inletAirTemp) 36322030d7c8Ssrikanta mondal { 36332030d7c8Ssrikanta mondal double value = 0; 36342030d7c8Ssrikanta mondal boost::system::error_code ec = ipmi::getDbusProperty( 36352030d7c8Ssrikanta mondal ctx, "xyz.openbmc_project.HwmonTempSensor", 36362030d7c8Ssrikanta mondal "/xyz/openbmc_project/sensors/temperature/Inlet_BRD_Temp", 36372030d7c8Ssrikanta mondal "xyz.openbmc_project.Sensor.Value", "Value", value); 36382030d7c8Ssrikanta mondal if (ec) 36392030d7c8Ssrikanta mondal { 36402030d7c8Ssrikanta mondal phosphor::logging::log<phosphor::logging::level::ERR>( 36412030d7c8Ssrikanta mondal "Failed to get BMC Get OEM temperature", 36422030d7c8Ssrikanta mondal phosphor::logging::entry("EXCEPTION=%s", ec.message().c_str())); 36432030d7c8Ssrikanta mondal return ipmi::responseUnspecifiedError(); 36442030d7c8Ssrikanta mondal } 36452030d7c8Ssrikanta mondal // Take the Inlet temperature 36462030d7c8Ssrikanta mondal oemReadingValue = static_cast<uint16_t>(value); 36472030d7c8Ssrikanta mondal } 36482030d7c8Ssrikanta mondal else 36492030d7c8Ssrikanta mondal { 36502030d7c8Ssrikanta mondal phosphor::logging::log<phosphor::logging::level::ERR>( 36512030d7c8Ssrikanta mondal "Currently Get OEM Reading support only for Inlet Air Temp"); 36522030d7c8Ssrikanta mondal return ipmi::responseParmOutOfRange(); 36532030d7c8Ssrikanta mondal } 36542030d7c8Ssrikanta mondal return ipmi::responseSuccess(domainId, readingType, oemReadingValue); 36552030d7c8Ssrikanta mondal } 36562030d7c8Ssrikanta mondal 365728972063SAppaRao Puli /** @brief implements the maximum size of 365828972063SAppaRao Puli * bridgeable messages used between KCS and 365928972063SAppaRao Puli * IPMB interfacesget security mode command. 366028972063SAppaRao Puli * 366128972063SAppaRao Puli * @returns IPMI completion code with following data 366228972063SAppaRao Puli * - KCS Buffer Size (In multiples of four bytes) 366328972063SAppaRao Puli * - IPMB Buffer Size (In multiples of four bytes) 366428972063SAppaRao Puli **/ 366528972063SAppaRao Puli ipmi::RspType<uint8_t, uint8_t> ipmiOEMGetBufferSize() 366628972063SAppaRao Puli { 366728972063SAppaRao Puli // for now this is hard coded; really this number is dependent on 366828972063SAppaRao Puli // the BMC kcs driver as well as the host kcs driver.... 366928972063SAppaRao Puli // we can't know the latter. 367028972063SAppaRao Puli uint8_t kcsMaxBufferSize = 63 / 4; 367128972063SAppaRao Puli uint8_t ipmbMaxBufferSize = 128 / 4; 367228972063SAppaRao Puli 367328972063SAppaRao Puli return ipmi::responseSuccess(kcsMaxBufferSize, ipmbMaxBufferSize); 367428972063SAppaRao Puli } 367528972063SAppaRao Puli 367664796041SJason M. Bills static void registerOEMFunctions(void) 3677a835eaa0SJia, Chunhui { 3678a835eaa0SJia, Chunhui phosphor::logging::log<phosphor::logging::level::INFO>( 3679a835eaa0SJia, Chunhui "Registering OEM commands"); 368098bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, 368198bbf69aSVernon Mauery intel::general::cmdGetChassisIdentifier, NULL, 368298bbf69aSVernon Mauery ipmiOEMGetChassisIdentifier, 3683a835eaa0SJia, Chunhui PRIVILEGE_USER); // get chassis identifier 368498bbf69aSVernon Mauery 368598bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetSystemGUID, 368664796041SJason M. Bills NULL, ipmiOEMSetSystemGUID, 3687a835eaa0SJia, Chunhui PRIVILEGE_ADMIN); // set system guid 3688b02bf095SJason M. Bills 3689b02bf095SJason M. Bills // <Disable BMC System Reset Action> 369098bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 369198bbf69aSVernon Mauery intel::general::cmdDisableBMCSystemReset, Privilege::Admin, 369298bbf69aSVernon Mauery ipmiOEMDisableBMCSystemReset); 369398bbf69aSVernon Mauery 3694b02bf095SJason M. Bills // <Get BMC Reset Disables> 369598bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 369698bbf69aSVernon Mauery intel::general::cmdGetBMCResetDisables, Privilege::Admin, 369798bbf69aSVernon Mauery ipmiOEMGetBMCResetDisables); 3698b02bf095SJason M. Bills 369998bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, intel::general::cmdSetBIOSID, 370064796041SJason M. Bills NULL, ipmiOEMSetBIOSID, PRIVILEGE_ADMIN); 3701cc49b54bSJia, Chunhui 37027a04f3a4SChen Yugang registerHandler(prioOemBase, intel::netFnGeneral, 37037a04f3a4SChen Yugang intel::general::cmdGetOEMDeviceInfo, Privilege::User, 37047a04f3a4SChen Yugang ipmiOEMGetDeviceInfo); 3705cc49b54bSJia, Chunhui 370698bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, 370798bbf69aSVernon Mauery intel::general::cmdGetAICSlotFRUIDSlotPosRecords, NULL, 370898bbf69aSVernon Mauery ipmiOEMGetAICFRU, PRIVILEGE_USER); 3709d509eb91SSuryakanth Sekar 371098bbf69aSVernon Mauery registerHandler(prioOpenBmcBase, intel::netFnGeneral, 371198bbf69aSVernon Mauery intel::general::cmdSendEmbeddedFWUpdStatus, 371298bbf69aSVernon Mauery Privilege::Operator, ipmiOEMSendEmbeddedFwUpdStatus); 3713d509eb91SSuryakanth Sekar 37142b664d5aSRajashekar Gade Reddy registerHandler(prioOpenBmcBase, intel::netFnApp, intel::app::cmdSlotIpmb, 37152b664d5aSRajashekar Gade Reddy Privilege::Admin, ipmiOEMSlotIpmb); 37162b664d5aSRajashekar Gade Reddy 371798bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, 371898bbf69aSVernon Mauery intel::general::cmdSetPowerRestoreDelay, NULL, 371998bbf69aSVernon Mauery ipmiOEMSetPowerRestoreDelay, PRIVILEGE_OPERATOR); 372098bbf69aSVernon Mauery 372198bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, 372298bbf69aSVernon Mauery intel::general::cmdGetPowerRestoreDelay, NULL, 372398bbf69aSVernon Mauery ipmiOEMGetPowerRestoreDelay, PRIVILEGE_USER); 372498bbf69aSVernon Mauery 372598bbf69aSVernon Mauery registerHandler(prioOpenBmcBase, intel::netFnGeneral, 372698bbf69aSVernon Mauery intel::general::cmdSetOEMUser2Activation, 372798bbf69aSVernon Mauery Privilege::Callback, ipmiOEMSetUser2Activation); 372898bbf69aSVernon Mauery 372998bbf69aSVernon Mauery registerHandler(prioOpenBmcBase, intel::netFnGeneral, 373098bbf69aSVernon Mauery intel::general::cmdSetSpecialUserPassword, 373198bbf69aSVernon Mauery Privilege::Callback, ipmiOEMSetSpecialUserPassword); 3732fc5e985bSRichard Marian Thomaiyar 373342bd9c8eSJason M. Bills // <Get Processor Error Config> 373498bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 373598bbf69aSVernon Mauery intel::general::cmdGetProcessorErrConfig, Privilege::User, 373698bbf69aSVernon Mauery ipmiOEMGetProcessorErrConfig); 373798bbf69aSVernon Mauery 373842bd9c8eSJason M. Bills // <Set Processor Error Config> 373998bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 374098bbf69aSVernon Mauery intel::general::cmdSetProcessorErrConfig, Privilege::Admin, 374198bbf69aSVernon Mauery ipmiOEMSetProcessorErrConfig); 374242bd9c8eSJason M. Bills 374398bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, 374498bbf69aSVernon Mauery intel::general::cmdSetShutdownPolicy, NULL, 374598bbf69aSVernon Mauery ipmiOEMSetShutdownPolicy, PRIVILEGE_ADMIN); 374691244a6aSJames Feist 374798bbf69aSVernon Mauery ipmiPrintAndRegister(intel::netFnGeneral, 374898bbf69aSVernon Mauery intel::general::cmdGetShutdownPolicy, NULL, 374998bbf69aSVernon Mauery ipmiOEMGetShutdownPolicy, PRIVILEGE_ADMIN); 375098bbf69aSVernon Mauery 3751f945eee0Sanil kumar appana registerHandler(prioOemBase, intel::netFnGeneral, 3752f945eee0Sanil kumar appana intel::general::cmdSetFanConfig, Privilege::User, 3753f945eee0Sanil kumar appana ipmiOEMSetFanConfig); 375491244a6aSJames Feist 375598bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 375698bbf69aSVernon Mauery intel::general::cmdGetFanConfig, Privilege::User, 375798bbf69aSVernon Mauery ipmiOEMGetFanConfig); 375891244a6aSJames Feist 375998bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 376098bbf69aSVernon Mauery intel::general::cmdGetFanSpeedOffset, Privilege::User, 376198bbf69aSVernon Mauery ipmiOEMGetFanSpeedOffset); 37625f957cafSJames Feist 376398bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 376498bbf69aSVernon Mauery intel::general::cmdSetFanSpeedOffset, Privilege::User, 376598bbf69aSVernon Mauery ipmiOEMSetFanSpeedOffset); 3766acc8a4ebSJames Feist 376798bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 376898bbf69aSVernon Mauery intel::general::cmdSetFscParameter, Privilege::User, 376998bbf69aSVernon Mauery ipmiOEMSetFscParameter); 3770acc8a4ebSJames Feist 377198bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 377298bbf69aSVernon Mauery intel::general::cmdGetFscParameter, Privilege::User, 377398bbf69aSVernon Mauery ipmiOEMGetFscParameter); 37745f957cafSJames Feist 377598bbf69aSVernon Mauery registerHandler(prioOpenBmcBase, intel::netFnGeneral, 377698bbf69aSVernon Mauery intel::general::cmdReadBaseBoardProductId, Privilege::Admin, 377798bbf69aSVernon Mauery ipmiOEMReadBoardProductId); 3778ea537d53SRichard Marian Thomaiyar 377998bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 378098bbf69aSVernon Mauery intel::general::cmdGetNmiStatus, Privilege::User, 378198bbf69aSVernon Mauery ipmiOEMGetNmiSource); 378239736d59SChen Yugang 378398bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 378498bbf69aSVernon Mauery intel::general::cmdSetNmiStatus, Privilege::Operator, 378598bbf69aSVernon Mauery ipmiOEMSetNmiSource); 378639736d59SChen Yugang 378798bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 378898bbf69aSVernon Mauery intel::general::cmdGetEfiBootOptions, Privilege::User, 378998bbf69aSVernon Mauery ipmiOemGetEfiBootOptions); 37904f7e76bbSChen,Yugang 379198bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 379298bbf69aSVernon Mauery intel::general::cmdSetEfiBootOptions, Privilege::Operator, 379398bbf69aSVernon Mauery ipmiOemSetEfiBootOptions); 37944f7e76bbSChen,Yugang 379598bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 379698bbf69aSVernon Mauery intel::general::cmdGetSecurityMode, Privilege::User, 379798bbf69aSVernon Mauery ipmiGetSecurityMode); 3798d801e463SRichard Marian Thomaiyar 379998bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 380098bbf69aSVernon Mauery intel::general::cmdSetSecurityMode, Privilege::Admin, 380198bbf69aSVernon Mauery ipmiSetSecurityMode); 3802d801e463SRichard Marian Thomaiyar 3803abd11ca3SNITIN SHARMA registerHandler(prioOemBase, intel::netFnGeneral, 3804abd11ca3SNITIN SHARMA intel::general::cmdGetLEDStatus, Privilege::Admin, 3805abd11ca3SNITIN SHARMA ipmiOEMGetLEDStatus); 38064ac799d7SVernon Mauery 380798bbf69aSVernon Mauery ipmiPrintAndRegister(ipmi::intel::netFnPlatform, 380898bbf69aSVernon Mauery ipmi::intel::platform::cmdCfgHostSerialPortSpeed, NULL, 380998bbf69aSVernon Mauery ipmiOEMCfgHostSerialPortSpeed, PRIVILEGE_ADMIN); 3810773703a5SCheng C Yang 381198bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 381298bbf69aSVernon Mauery intel::general::cmdSetFaultIndication, Privilege::Operator, 381398bbf69aSVernon Mauery ipmiOEMSetFaultIndication); 381498bbf69aSVernon Mauery 381598bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 381698bbf69aSVernon Mauery intel::general::cmdSetColdRedundancyConfig, Privilege::User, 381798bbf69aSVernon Mauery ipmiOEMSetCRConfig); 381898bbf69aSVernon Mauery 381998bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 382098bbf69aSVernon Mauery intel::general::cmdGetColdRedundancyConfig, Privilege::User, 382198bbf69aSVernon Mauery ipmiOEMGetCRConfig); 382298bbf69aSVernon Mauery 382398bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 382498bbf69aSVernon Mauery intel::general::cmdRestoreConfiguration, Privilege::Admin, 38254ac799d7SVernon Mauery ipmiRestoreConfiguration); 382663efafacSJames Feist 382798bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 382898bbf69aSVernon Mauery intel::general::cmdSetDimmOffset, Privilege::Operator, 382998bbf69aSVernon Mauery ipmiOEMSetDimmOffset); 383063efafacSJames Feist 383198bbf69aSVernon Mauery registerHandler(prioOemBase, intel::netFnGeneral, 383298bbf69aSVernon Mauery intel::general::cmdGetDimmOffset, Privilege::Operator, 383398bbf69aSVernon Mauery ipmiOEMGetDimmOffset); 3834ca12a7beSChen Yugang 38354e6ee15bSCheng C Yang registerHandler(prioOemBase, intel::netFnGeneral, 38364e6ee15bSCheng C Yang intel::general::cmdGetPSUVersion, Privilege::User, 38374e6ee15bSCheng C Yang ipmiOEMGetPSUVersion); 383828972063SAppaRao Puli 383928972063SAppaRao Puli registerHandler(prioOemBase, intel::netFnGeneral, 384028972063SAppaRao Puli intel::general::cmdGetBufferSize, Privilege::User, 384128972063SAppaRao Puli ipmiOEMGetBufferSize); 38422030d7c8Ssrikanta mondal 38432030d7c8Ssrikanta mondal registerHandler(prioOemBase, intel::netFnGeneral, 38442030d7c8Ssrikanta mondal intel::general::cmdOEMGetReading, Privilege::User, 38452030d7c8Ssrikanta mondal ipmiOEMGetReading); 3846a835eaa0SJia, Chunhui } 3847a835eaa0SJia, Chunhui 3848a835eaa0SJia, Chunhui } // namespace ipmi 3849