1a3702c1fSVernon Mauery /* 2a3702c1fSVernon Mauery // Copyright (c) 2018 Intel Corporation 3a3702c1fSVernon Mauery // 4a3702c1fSVernon Mauery // Licensed under the Apache License, Version 2.0 (the "License"); 5a3702c1fSVernon Mauery // you may not use this file except in compliance with the License. 6a3702c1fSVernon Mauery // You may obtain a copy of the License at 7a3702c1fSVernon Mauery // 8a3702c1fSVernon Mauery // http://www.apache.org/licenses/LICENSE-2.0 9a3702c1fSVernon Mauery // 10a3702c1fSVernon Mauery // Unless required by applicable law or agreed to in writing, software 11a3702c1fSVernon Mauery // distributed under the License is distributed on an "AS IS" BASIS, 12a3702c1fSVernon Mauery // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a3702c1fSVernon Mauery // See the License for the specific language governing permissions and 14a3702c1fSVernon Mauery // limitations under the License. 15a3702c1fSVernon Mauery */ 16a3702c1fSVernon Mauery 17d872a4a4SAyushi Smriti #include <linux/input.h> 18d872a4a4SAyushi Smriti 1906584cd0SArun P. Mohanan #include <boost/algorithm/string.hpp> 20147daec5SRichard Marian Thomaiyar #include <boost/container/flat_map.hpp> 21a3702c1fSVernon Mauery #include <ipmid/api.hpp> 22a3702c1fSVernon Mauery #include <manufacturingcommands.hpp> 23a3702c1fSVernon Mauery #include <oemcommands.hpp> 244180cfe9SAlex Schendel #include <phosphor-logging/lg2.hpp> 250748c69dSJason M. Bills #include <types.hpp> 26a3702c1fSVernon Mauery 27*97c30909SVasu V #include <charconv> 28fcd2d3a9SJames Feist #include <filesystem> 29fcd2d3a9SJames Feist #include <fstream> 30fcd2d3a9SJames Feist 31a3702c1fSVernon Mauery namespace ipmi 32a3702c1fSVernon Mauery { 33a3702c1fSVernon Mauery 34a3702c1fSVernon Mauery Manufacturing mtm; 35a3702c1fSVernon Mauery 36a3702c1fSVernon Mauery static auto revertTimeOut = 37a3702c1fSVernon Mauery std::chrono::duration_cast<std::chrono::microseconds>( 38a3702c1fSVernon Mauery std::chrono::seconds(60)); // 1 minute timeout 39a3702c1fSVernon Mauery 407acb2d27SV-Sanjana static constexpr uint8_t bbRiserMux = 0; 417acb2d27SV-Sanjana static constexpr uint8_t leftRiserMux = 1; 427acb2d27SV-Sanjana static constexpr uint8_t rightRiserMux = 2; 437acb2d27SV-Sanjana static constexpr uint8_t pcieMux = 3; 447acb2d27SV-Sanjana static constexpr uint8_t hsbpMux = 4; 457acb2d27SV-Sanjana 46f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0; 47f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1; 48f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35; 49f267a67dSYong Li 50a3702c1fSVernon Mauery static constexpr const char* callbackMgrService = 51a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 52a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf = 53a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 54a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath = 55a3702c1fSVernon Mauery "/xyz/openbmc_project/CallbackManager"; 56a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; 57a3702c1fSVernon Mauery 58a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1"; 59a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; 60a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf = 61a3702c1fSVernon Mauery "org.freedesktop.systemd1.Manager"; 62a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service"; 63a3702c1fSVernon Mauery 64357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx) 65666dd01cSRichard Marian Thomaiyar { 66666dd01cSRichard Marian Thomaiyar boost::system::error_code ec; 67357ddc74SRichard Marian Thomaiyar ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService, 68666dd01cSRichard Marian Thomaiyar specialModeObjPath, specialModeIntf, 69666dd01cSRichard Marian Thomaiyar "ResetTimer"); 70666dd01cSRichard Marian Thomaiyar if (ec) 71666dd01cSRichard Marian Thomaiyar { 724180cfe9SAlex Schendel lg2::error("Failed to reset the manufacturing mode timer"); 73666dd01cSRichard Marian Thomaiyar return ccUnspecifiedError; 74666dd01cSRichard Marian Thomaiyar } 75666dd01cSRichard Marian Thomaiyar return ccSuccess; 76666dd01cSRichard Marian Thomaiyar } 77666dd01cSRichard Marian Thomaiyar 7838d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) 79a3702c1fSVernon Mauery { 8038d2b5a6SJason M. Bills switch (signal) 8138d2b5a6SJason M. Bills { 8238d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 8338d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/power"; 8438d2b5a6SJason M. Bills break; 8538d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 8638d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/reset"; 8738d2b5a6SJason M. Bills break; 8838d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 8938d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/nmi"; 9038d2b5a6SJason M. Bills break; 918e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 928e5e2b04SRichard Marian Thomaiyar path = "/xyz/openbmc_project/chassis/buttons/id"; 938e5e2b04SRichard Marian Thomaiyar break; 9438d2b5a6SJason M. Bills default: 9538d2b5a6SJason M. Bills return -1; 9638d2b5a6SJason M. Bills break; 9738d2b5a6SJason M. Bills } 9838d2b5a6SJason M. Bills return 0; 99a3702c1fSVernon Mauery } 100a3702c1fSVernon Mauery 10137890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState) 102a3702c1fSVernon Mauery { 103a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 104a3702c1fSVernon Mauery if (ledProp == nullptr) 105a3702c1fSVernon Mauery { 106a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 107a3702c1fSVernon Mauery } 108a3702c1fSVernon Mauery 109a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 110a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 111a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 112a3702c1fSVernon Mauery ipmi::Value presentState; 113a3702c1fSVernon Mauery 114a3702c1fSVernon Mauery if (false == ledProp->getLock()) 115a3702c1fSVernon Mauery { 116a3702c1fSVernon Mauery if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, 117a3702c1fSVernon Mauery "State", &presentState) != 0) 118a3702c1fSVernon Mauery { 119a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 120a3702c1fSVernon Mauery } 121a3702c1fSVernon Mauery ledProp->setPrevState(std::get<std::string>(presentState)); 122a3702c1fSVernon Mauery ledProp->setLock(true); 123a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 124a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 125a3702c1fSVernon Mauery { 126a3702c1fSVernon Mauery mtm.revertLedCallback = true; 127a3702c1fSVernon Mauery } 128a3702c1fSVernon Mauery } 12938d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 130a3702c1fSVernon Mauery ledStateStr + setState) != 0) 131a3702c1fSVernon Mauery { 132a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 133a3702c1fSVernon Mauery } 134a3702c1fSVernon Mauery return IPMI_CC_OK; 135a3702c1fSVernon Mauery } 136a3702c1fSVernon Mauery 137a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal) 138a3702c1fSVernon Mauery { 139a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 140a3702c1fSVernon Mauery if (ledProp == nullptr) 141a3702c1fSVernon Mauery { 142a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 143a3702c1fSVernon Mauery } 144a3702c1fSVernon Mauery if (true == ledProp->getLock()) 145a3702c1fSVernon Mauery { 146a3702c1fSVernon Mauery ledProp->setLock(false); 147a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 148a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 149a3702c1fSVernon Mauery { 150a3702c1fSVernon Mauery try 151a3702c1fSVernon Mauery { 152a3702c1fSVernon Mauery ipmi::method_no_args::callDbusMethod( 153a3702c1fSVernon Mauery *getSdBus(), callbackMgrService, callbackMgrObjPath, 154a3702c1fSVernon Mauery callbackMgrIntf, retriggerLedUpdate); 155a3702c1fSVernon Mauery } 156bd51e6a9SPatrick Williams catch (const sdbusplus::exception_t& e) 157a3702c1fSVernon Mauery { 158a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 159a3702c1fSVernon Mauery } 160a3702c1fSVernon Mauery mtm.revertLedCallback = false; 161a3702c1fSVernon Mauery } 162a3702c1fSVernon Mauery else 163a3702c1fSVernon Mauery { 164a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 165a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 166a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 16738d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 16838d2b5a6SJason M. Bills ledProp->getPrevState()) != 0) 169a3702c1fSVernon Mauery { 170a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 171a3702c1fSVernon Mauery } 172a3702c1fSVernon Mauery } 173a3702c1fSVernon Mauery } 174a3702c1fSVernon Mauery return IPMI_CC_OK; 175a3702c1fSVernon Mauery } 176a3702c1fSVernon Mauery 177a3702c1fSVernon Mauery void Manufacturing::initData() 178a3702c1fSVernon Mauery { 179a3702c1fSVernon Mauery ledPropertyList.push_back( 180a3702c1fSVernon Mauery LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); 181a3702c1fSVernon Mauery ledPropertyList.push_back( 182a3702c1fSVernon Mauery LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); 183a3702c1fSVernon Mauery ledPropertyList.push_back( 184a3702c1fSVernon Mauery LedProperty(SmSignalSet::smIdentifyLed, "identify")); 185a3702c1fSVernon Mauery } 186a3702c1fSVernon Mauery 187a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler() 188a3702c1fSVernon Mauery { 189ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE 190ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::valUnsecure) 191ae13ac62SRichard Marian Thomaiyar { 192ae13ac62SRichard Marian Thomaiyar // Don't revert the behaviour for validation unsecure mode. 193ae13ac62SRichard Marian Thomaiyar return; 194ae13ac62SRichard Marian Thomaiyar } 195ae13ac62SRichard Marian Thomaiyar #endif 196a3702c1fSVernon Mauery if (revertFanPWM) 197a3702c1fSVernon Mauery { 198a3702c1fSVernon Mauery revertFanPWM = false; 199a3702c1fSVernon Mauery disablePidControlService(false); 200a3702c1fSVernon Mauery } 201a3702c1fSVernon Mauery 202d872a4a4SAyushi Smriti if (mtmTestBeepFd != -1) 203d872a4a4SAyushi Smriti { 204d872a4a4SAyushi Smriti ::close(mtmTestBeepFd); 205d872a4a4SAyushi Smriti mtmTestBeepFd = -1; 206d872a4a4SAyushi Smriti } 207d872a4a4SAyushi Smriti 208a3702c1fSVernon Mauery for (const auto& ledProperty : ledPropertyList) 209a3702c1fSVernon Mauery { 210a3702c1fSVernon Mauery const std::string& ledName = ledProperty.getName(); 211f365614cSJayaprakash Mutyala if (ledName == "identify" && mtm.getMfgMode() == SpecialMode::mfg) 212f365614cSJayaprakash Mutyala { 213f365614cSJayaprakash Mutyala // Don't revert the behaviour for manufacturing mode 214f365614cSJayaprakash Mutyala continue; 215f365614cSJayaprakash Mutyala } 216a3702c1fSVernon Mauery ledRevert(ledProperty.getSignal()); 217a3702c1fSVernon Mauery } 218a3702c1fSVernon Mauery } 219a3702c1fSVernon Mauery 220a3702c1fSVernon Mauery Manufacturing::Manufacturing() : 221a3702c1fSVernon Mauery revertTimer([&](void) { revertTimerHandler(); }) 222a3702c1fSVernon Mauery { 223a3702c1fSVernon Mauery initData(); 224a3702c1fSVernon Mauery } 225a3702c1fSVernon Mauery 22638d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service, 22738d2b5a6SJason M. Bills const std::string& path, 22838d2b5a6SJason M. Bills const std::string& interface, 22938d2b5a6SJason M. Bills const std::string& propertyName, 23038d2b5a6SJason M. Bills ipmi::Value* reply) 231a3702c1fSVernon Mauery { 232a3702c1fSVernon Mauery try 233a3702c1fSVernon Mauery { 23438d2b5a6SJason M. Bills *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, 23538d2b5a6SJason M. Bills propertyName); 236a3702c1fSVernon Mauery } 237f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 238a3702c1fSVernon Mauery { 2394180cfe9SAlex Schendel lg2::info("ERROR: getProperty"); 240a3702c1fSVernon Mauery return -1; 241a3702c1fSVernon Mauery } 242a3702c1fSVernon Mauery 243a3702c1fSVernon Mauery return 0; 244a3702c1fSVernon Mauery } 245a3702c1fSVernon Mauery 24638d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service, 24738d2b5a6SJason M. Bills const std::string& path, 24838d2b5a6SJason M. Bills const std::string& interface, 24938d2b5a6SJason M. Bills const std::string& propertyName, 25038d2b5a6SJason M. Bills ipmi::Value value) 251a3702c1fSVernon Mauery { 252a3702c1fSVernon Mauery try 253a3702c1fSVernon Mauery { 25438d2b5a6SJason M. Bills ipmi::setDbusProperty(*getSdBus(), service, path, interface, 255a3702c1fSVernon Mauery propertyName, value); 256a3702c1fSVernon Mauery } 257f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 258a3702c1fSVernon Mauery { 2594180cfe9SAlex Schendel lg2::info("ERROR: setProperty"); 260a3702c1fSVernon Mauery return -1; 261a3702c1fSVernon Mauery } 262a3702c1fSVernon Mauery 263a3702c1fSVernon Mauery return 0; 264a3702c1fSVernon Mauery } 265a3702c1fSVernon Mauery 266a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable) 267a3702c1fSVernon Mauery { 268a3702c1fSVernon Mauery try 269a3702c1fSVernon Mauery { 270a3702c1fSVernon Mauery auto dbus = getSdBus(); 271a3702c1fSVernon Mauery auto method = dbus->new_method_call(systemDService, systemDObjPath, 272a3702c1fSVernon Mauery systemDMgrIntf, 273a3702c1fSVernon Mauery disable ? "StopUnit" : "StartUnit"); 274a3702c1fSVernon Mauery method.append(pidControlService, "replace"); 275a3702c1fSVernon Mauery auto reply = dbus->call(method); 276a3702c1fSVernon Mauery } 277f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 278a3702c1fSVernon Mauery { 2794180cfe9SAlex Schendel lg2::info("ERROR: phosphor-pid-control service start or stop failed"); 280a3702c1fSVernon Mauery return -1; 281a3702c1fSVernon Mauery } 282a3702c1fSVernon Mauery return 0; 283a3702c1fSVernon Mauery } 284a3702c1fSVernon Mauery 28590eb7876SAlex Schendel static bool findPwmName(ipmi::Context::ptr& ctx, uint8_t instance, 28690eb7876SAlex Schendel std::string& pwmName) 28790eb7876SAlex Schendel { 28890eb7876SAlex Schendel boost::system::error_code ec{}; 28990eb7876SAlex Schendel ObjectValueTree obj; 29090eb7876SAlex Schendel 29190eb7876SAlex Schendel // GetAll the objects under service FruDevice 29290eb7876SAlex Schendel ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager", 29390eb7876SAlex Schendel "/xyz/openbmc_project/inventory", obj); 29490eb7876SAlex Schendel if (ec) 29590eb7876SAlex Schendel { 2964180cfe9SAlex Schendel lg2::error("GetMangagedObjects failed", "ERROR", ec.message().c_str()); 29790eb7876SAlex Schendel return false; 29890eb7876SAlex Schendel } 29990eb7876SAlex Schendel for (const auto& [path, objData] : obj) 30090eb7876SAlex Schendel { 30190eb7876SAlex Schendel for (const auto& [intf, propMap] : objData) 30290eb7876SAlex Schendel { 30390eb7876SAlex Schendel // Currently, these are the three different fan types supported. 30490eb7876SAlex Schendel if (intf == "xyz.openbmc_project.Configuration.AspeedFan" || 30590eb7876SAlex Schendel intf == "xyz.openbmc_project.Configuration.I2CFan" || 30690eb7876SAlex Schendel intf == "xyz.openbmc_project.Configuration.NuvotonFan") 30790eb7876SAlex Schendel { 3084180cfe9SAlex Schendel std::string fanPath = "/Fan_"; 30990eb7876SAlex Schendel 3104180cfe9SAlex Schendel fanPath += std::to_string(instance); 3114180cfe9SAlex Schendel std::string objPath = path.str; 3124180cfe9SAlex Schendel objPath = objPath.substr(objPath.find_last_of("/")); 3134180cfe9SAlex Schendel if (objPath != fanPath) 31490eb7876SAlex Schendel { 31590eb7876SAlex Schendel continue; 31690eb7876SAlex Schendel } 31790eb7876SAlex Schendel auto connector = objData.find(intf + std::string(".Connector")); 31890eb7876SAlex Schendel if (connector == objData.end()) 31990eb7876SAlex Schendel { 32090eb7876SAlex Schendel return false; 32190eb7876SAlex Schendel } 32290eb7876SAlex Schendel auto findPwmName = connector->second.find("PwmName"); 32390eb7876SAlex Schendel if (findPwmName != connector->second.end()) 32490eb7876SAlex Schendel { 32590eb7876SAlex Schendel auto fanPwmName = 32690eb7876SAlex Schendel std::get_if<std::string>(&findPwmName->second); 32790eb7876SAlex Schendel if (!fanPwmName) 32890eb7876SAlex Schendel { 3294180cfe9SAlex Schendel lg2::error("PwmName parse ERROR."); 33090eb7876SAlex Schendel return false; 33190eb7876SAlex Schendel } 33290eb7876SAlex Schendel pwmName = *fanPwmName; 33390eb7876SAlex Schendel return true; 33490eb7876SAlex Schendel } 33590eb7876SAlex Schendel auto findPwm = connector->second.find("Pwm"); 33690eb7876SAlex Schendel if (findPwm == connector->second.end()) 33790eb7876SAlex Schendel { 33890eb7876SAlex Schendel return false; 33990eb7876SAlex Schendel } 34090eb7876SAlex Schendel auto fanPwm = std::get_if<uint64_t>(&findPwm->second); 34190eb7876SAlex Schendel if (!fanPwm) 34290eb7876SAlex Schendel { 34390eb7876SAlex Schendel return false; 34490eb7876SAlex Schendel } 34590eb7876SAlex Schendel pwmName = "Pwm_" + std::to_string(*fanPwm + 1); 34690eb7876SAlex Schendel return true; 34790eb7876SAlex Schendel } 34890eb7876SAlex Schendel } 34990eb7876SAlex Schendel } 35090eb7876SAlex Schendel return false; 35190eb7876SAlex Schendel } 35238d2b5a6SJason M. Bills ipmi::RspType<uint8_t, // Signal value 35338d2b5a6SJason M. Bills std::optional<uint16_t> // Fan tach value 35438d2b5a6SJason M. Bills > 355357ddc74SRichard Marian Thomaiyar appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 356147daec5SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte) 357a3702c1fSVernon Mauery { 358e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM get signal command only in 359e0511e5fSAyushi Smriti // manfacturing mode. 36038d2b5a6SJason M. Bills 36138d2b5a6SJason M. Bills SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); 36238d2b5a6SJason M. Bills SmActionGet action = static_cast<SmActionGet>(actionByte); 36338d2b5a6SJason M. Bills 36438d2b5a6SJason M. Bills switch (signalType) 36538d2b5a6SJason M. Bills { 36698705b39Sanil kumar appana case SmSignalGet::smChassisIntrusion: 36798705b39Sanil kumar appana { 36898705b39Sanil kumar appana ipmi::Value reply; 36998705b39Sanil kumar appana if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf, 37098705b39Sanil kumar appana "Status", &reply) < 0) 37198705b39Sanil kumar appana { 37298705b39Sanil kumar appana return ipmi::responseInvalidFieldRequest(); 37398705b39Sanil kumar appana } 37498705b39Sanil kumar appana std::string* intrusionStatus = std::get_if<std::string>(&reply); 37598705b39Sanil kumar appana if (!intrusionStatus) 37698705b39Sanil kumar appana { 37798705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 37898705b39Sanil kumar appana } 37998705b39Sanil kumar appana 38098705b39Sanil kumar appana uint8_t status = 0; 38198705b39Sanil kumar appana if (!intrusionStatus->compare("Normal")) 38298705b39Sanil kumar appana { 38398705b39Sanil kumar appana status = static_cast<uint8_t>(IntrusionStatus::normal); 38498705b39Sanil kumar appana } 38598705b39Sanil kumar appana else if (!intrusionStatus->compare("HardwareIntrusion")) 38698705b39Sanil kumar appana { 38798705b39Sanil kumar appana status = 38898705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion); 38998705b39Sanil kumar appana } 39098705b39Sanil kumar appana else if (!intrusionStatus->compare("TamperingDetected")) 39198705b39Sanil kumar appana { 39298705b39Sanil kumar appana status = 39398705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::tamperingDetected); 39498705b39Sanil kumar appana } 39598705b39Sanil kumar appana else 39698705b39Sanil kumar appana { 39798705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 39898705b39Sanil kumar appana } 39998705b39Sanil kumar appana return ipmi::responseSuccess(status, std::nullopt); 40098705b39Sanil kumar appana } 40138d2b5a6SJason M. Bills case SmSignalGet::smFanPwmGet: 40238d2b5a6SJason M. Bills { 403a3702c1fSVernon Mauery ipmi::Value reply; 40490eb7876SAlex Schendel std::string pwmName, fullPath; 4054180cfe9SAlex Schendel if (!findPwmName(ctx, instance + 1, pwmName)) 40690eb7876SAlex Schendel { 40790eb7876SAlex Schendel // The default PWM name is Pwm_# 40890eb7876SAlex Schendel pwmName = "Pwm_" + std::to_string(instance + 1); 40990eb7876SAlex Schendel } 41090eb7876SAlex Schendel fullPath = fanPwmPath + pwmName; 41138d2b5a6SJason M. Bills if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 41238d2b5a6SJason M. Bills &reply) < 0) 41338d2b5a6SJason M. Bills { 41438d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 41538d2b5a6SJason M. Bills } 41638d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 41738d2b5a6SJason M. Bills if (doubleVal == nullptr) 41838d2b5a6SJason M. Bills { 41938d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 42038d2b5a6SJason M. Bills } 42138d2b5a6SJason M. Bills uint8_t sensorVal = std::round(*doubleVal); 422357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 42338d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 42438d2b5a6SJason M. Bills } 42538d2b5a6SJason M. Bills break; 42638d2b5a6SJason M. Bills case SmSignalGet::smFanTachometerGet: 42738d2b5a6SJason M. Bills { 428147daec5SRichard Marian Thomaiyar boost::system::error_code ec; 429147daec5SRichard Marian Thomaiyar using objFlatMap = boost::container::flat_map< 430147daec5SRichard Marian Thomaiyar std::string, boost::container::flat_map< 431147daec5SRichard Marian Thomaiyar std::string, std::vector<std::string>>>; 432147daec5SRichard Marian Thomaiyar 433357ddc74SRichard Marian Thomaiyar auto flatMap = ctx->bus->yield_method_call<objFlatMap>( 434357ddc74SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 435147daec5SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 436147daec5SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTree", 437147daec5SRichard Marian Thomaiyar fanTachBasePath, 0, std::array<const char*, 1>{fanIntf}); 438147daec5SRichard Marian Thomaiyar if (ec) 439147daec5SRichard Marian Thomaiyar { 4404180cfe9SAlex Schendel lg2::error("Failed to query fan tach sub tree objects"); 441147daec5SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 442147daec5SRichard Marian Thomaiyar } 443147daec5SRichard Marian Thomaiyar if (instance >= flatMap.size()) 44438d2b5a6SJason M. Bills { 44538d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 44638d2b5a6SJason M. Bills } 447147daec5SRichard Marian Thomaiyar auto itr = flatMap.nth(instance); 44838d2b5a6SJason M. Bills ipmi::Value reply; 449147daec5SRichard Marian Thomaiyar if (mtm.getProperty(fanService, itr->first, fanIntf, "Value", 45038d2b5a6SJason M. Bills &reply) < 0) 45138d2b5a6SJason M. Bills { 45238d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 45338d2b5a6SJason M. Bills } 45438d2b5a6SJason M. Bills 45538d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 45638d2b5a6SJason M. Bills if (doubleVal == nullptr) 45738d2b5a6SJason M. Bills { 45838d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 45938d2b5a6SJason M. Bills } 46038d2b5a6SJason M. Bills uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; 46138d2b5a6SJason M. Bills std::optional<uint16_t> fanTach = std::round(*doubleVal); 46238d2b5a6SJason M. Bills 463357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 46438d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, fanTach); 46538d2b5a6SJason M. Bills } 46638d2b5a6SJason M. Bills break; 4678e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 4688e5e2b04SRichard Marian Thomaiyar { 4698e5e2b04SRichard Marian Thomaiyar if (action == SmActionGet::revert || action == SmActionGet::ignore) 4708e5e2b04SRichard Marian Thomaiyar { 4718e5e2b04SRichard Marian Thomaiyar // ButtonMasked property is not supported for ID button as it is 4728e5e2b04SRichard Marian Thomaiyar // unnecessary. Hence if requested for revert / ignore, override 4738e5e2b04SRichard Marian Thomaiyar // it to sample action to make tools happy. 4748e5e2b04SRichard Marian Thomaiyar action = SmActionGet::sample; 4758e5e2b04SRichard Marian Thomaiyar } 4768e5e2b04SRichard Marian Thomaiyar // fall-through 4778e5e2b04SRichard Marian Thomaiyar } 47838d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 47938d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 48038d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 48138d2b5a6SJason M. Bills { 48238d2b5a6SJason M. Bills std::string path; 48338d2b5a6SJason M. Bills if (getGpioPathForSmSignal(signalType, path) < 0) 48438d2b5a6SJason M. Bills { 48538d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 48638d2b5a6SJason M. Bills } 487a3702c1fSVernon Mauery 488a3702c1fSVernon Mauery switch (action) 489a3702c1fSVernon Mauery { 490a3702c1fSVernon Mauery case SmActionGet::sample: 4914180cfe9SAlex Schendel lg2::info("case SmActionGet::sample"); 492a3702c1fSVernon Mauery break; 493a3702c1fSVernon Mauery case SmActionGet::ignore: 494a3702c1fSVernon Mauery { 4954180cfe9SAlex Schendel lg2::info("case SmActionGet::ignore"); 49638d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 49738d2b5a6SJason M. Bills "ButtonMasked", true) < 0) 498a3702c1fSVernon Mauery { 49938d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 500a3702c1fSVernon Mauery } 501a3702c1fSVernon Mauery } 502a3702c1fSVernon Mauery break; 503a3702c1fSVernon Mauery case SmActionGet::revert: 504a3702c1fSVernon Mauery { 5054180cfe9SAlex Schendel lg2::info("case SmActionGet::revert"); 50638d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 50738d2b5a6SJason M. Bills "ButtonMasked", false) < 0) 508a3702c1fSVernon Mauery { 50938d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 510a3702c1fSVernon Mauery } 511a3702c1fSVernon Mauery } 512a3702c1fSVernon Mauery break; 513a3702c1fSVernon Mauery 514a3702c1fSVernon Mauery default: 51538d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 516a3702c1fSVernon Mauery break; 517a3702c1fSVernon Mauery } 518a3702c1fSVernon Mauery 519a3702c1fSVernon Mauery ipmi::Value reply; 52038d2b5a6SJason M. Bills if (mtm.getProperty(buttonService, path, buttonIntf, 52138d2b5a6SJason M. Bills "ButtonPressed", &reply) < 0) 522a3702c1fSVernon Mauery { 52338d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 524a3702c1fSVernon Mauery } 52538d2b5a6SJason M. Bills bool* valPtr = std::get_if<bool>(&reply); 52638d2b5a6SJason M. Bills if (valPtr == nullptr) 527a3702c1fSVernon Mauery { 52838d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 529a3702c1fSVernon Mauery } 530357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 53138d2b5a6SJason M. Bills uint8_t sensorVal = *valPtr; 53238d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 533a3702c1fSVernon Mauery } 534a3702c1fSVernon Mauery break; 5351b74a210SRichard Marian Thomaiyar case SmSignalGet::smNcsiDiag: 5361b74a210SRichard Marian Thomaiyar { 5371b74a210SRichard Marian Thomaiyar constexpr const char* netBasePath = "/sys/class/net/eth"; 5381b74a210SRichard Marian Thomaiyar constexpr const char* carrierSuffix = "/carrier"; 5391b74a210SRichard Marian Thomaiyar std::ifstream netIfs(netBasePath + std::to_string(instance) + 5401b74a210SRichard Marian Thomaiyar carrierSuffix); 5411b74a210SRichard Marian Thomaiyar if (!netIfs.good()) 5421b74a210SRichard Marian Thomaiyar { 5431b74a210SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 5441b74a210SRichard Marian Thomaiyar } 5451b74a210SRichard Marian Thomaiyar std::string carrier; 5461b74a210SRichard Marian Thomaiyar netIfs >> carrier; 547357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 5481b74a210SRichard Marian Thomaiyar return ipmi::responseSuccess( 5491b74a210SRichard Marian Thomaiyar static_cast<uint8_t>(std::stoi(carrier)), std::nullopt); 5501b74a210SRichard Marian Thomaiyar } 5511b74a210SRichard Marian Thomaiyar break; 552a3702c1fSVernon Mauery default: 55338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 554a3702c1fSVernon Mauery break; 555a3702c1fSVernon Mauery } 556a3702c1fSVernon Mauery } 557a3702c1fSVernon Mauery 558357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 559357ddc74SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte, 5605e3bf557SAyushi Smriti std::optional<uint8_t> pwmSpeed) 561a3702c1fSVernon Mauery { 562e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM set signal command only in 563e0511e5fSAyushi Smriti // manfacturing mode. 5645e3bf557SAyushi Smriti 5655e3bf557SAyushi Smriti SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte); 5665e3bf557SAyushi Smriti SmActionSet action = static_cast<SmActionSet>(actionByte); 5675e3bf557SAyushi Smriti Cc retCode = ccSuccess; 56813b0039dSJames Feist int8_t ret = 0; 5695e3bf557SAyushi Smriti 5705e3bf557SAyushi Smriti switch (signalType) 571a3702c1fSVernon Mauery { 572a3702c1fSVernon Mauery case SmSignalSet::smPowerFaultLed: 573a3702c1fSVernon Mauery case SmSignalSet::smSystemReadyLed: 574a3702c1fSVernon Mauery case SmSignalSet::smIdentifyLed: 5755e3bf557SAyushi Smriti switch (action) 576a3702c1fSVernon Mauery { 577a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 578a3702c1fSVernon Mauery { 5794180cfe9SAlex Schendel lg2::info("case SmActionSet::forceDeasserted"); 580a3702c1fSVernon Mauery 5815e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("Off")); 5825e3bf557SAyushi Smriti if (retCode != ccSuccess) 583a3702c1fSVernon Mauery { 5845e3bf557SAyushi Smriti return ipmi::response(retCode); 585a3702c1fSVernon Mauery } 586a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 587a3702c1fSVernon Mauery } 588a3702c1fSVernon Mauery break; 589a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 590a3702c1fSVernon Mauery { 5914180cfe9SAlex Schendel lg2::info("case SmActionSet::forceAsserted"); 592a3702c1fSVernon Mauery 5935e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("On")); 5945e3bf557SAyushi Smriti if (retCode != ccSuccess) 595a3702c1fSVernon Mauery { 5965e3bf557SAyushi Smriti return ipmi::response(retCode); 597a3702c1fSVernon Mauery } 598a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 5995e3bf557SAyushi Smriti if (SmSignalSet::smPowerFaultLed == signalType) 600a3702c1fSVernon Mauery { 601a3702c1fSVernon Mauery // Deassert "system ready" 6025e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed, 603a3702c1fSVernon Mauery std::string("Off")); 604a3702c1fSVernon Mauery } 6055e3bf557SAyushi Smriti else if (SmSignalSet::smSystemReadyLed == signalType) 606a3702c1fSVernon Mauery { 607a3702c1fSVernon Mauery // Deassert "fault led" 6085e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed, 609a3702c1fSVernon Mauery std::string("Off")); 610a3702c1fSVernon Mauery } 611a3702c1fSVernon Mauery } 612a3702c1fSVernon Mauery break; 613a3702c1fSVernon Mauery case SmActionSet::revert: 614a3702c1fSVernon Mauery { 6154180cfe9SAlex Schendel lg2::info("case SmActionSet::revert"); 6165e3bf557SAyushi Smriti retCode = ledRevert(signalType); 617a3702c1fSVernon Mauery } 618a3702c1fSVernon Mauery break; 619a3702c1fSVernon Mauery default: 620a3702c1fSVernon Mauery { 6215e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 622a3702c1fSVernon Mauery } 623a3702c1fSVernon Mauery } 624a3702c1fSVernon Mauery break; 625a3702c1fSVernon Mauery case SmSignalSet::smFanPowerSpeed: 626a3702c1fSVernon Mauery { 6275e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (!pwmSpeed)) 628a3702c1fSVernon Mauery { 6295e3bf557SAyushi Smriti return ipmi::responseReqDataLenInvalid(); 630a3702c1fSVernon Mauery } 6315e3bf557SAyushi Smriti 6325e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100)) 6335e3bf557SAyushi Smriti { 6345e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 6355e3bf557SAyushi Smriti } 6365e3bf557SAyushi Smriti 637a3702c1fSVernon Mauery uint8_t pwmValue = 0; 6385e3bf557SAyushi Smriti switch (action) 639a3702c1fSVernon Mauery { 640a3702c1fSVernon Mauery case SmActionSet::revert: 641a3702c1fSVernon Mauery { 642a3702c1fSVernon Mauery if (mtm.revertFanPWM) 643a3702c1fSVernon Mauery { 644a3702c1fSVernon Mauery ret = mtm.disablePidControlService(false); 645a3702c1fSVernon Mauery if (ret < 0) 646a3702c1fSVernon Mauery { 6475e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 648a3702c1fSVernon Mauery } 649a3702c1fSVernon Mauery mtm.revertFanPWM = false; 650a3702c1fSVernon Mauery } 651a3702c1fSVernon Mauery } 652a3702c1fSVernon Mauery break; 653a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 654a3702c1fSVernon Mauery { 6555e3bf557SAyushi Smriti pwmValue = *pwmSpeed; 656a3702c1fSVernon Mauery } // fall-through 657a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 658a3702c1fSVernon Mauery { 659a3702c1fSVernon Mauery if (!mtm.revertFanPWM) 660a3702c1fSVernon Mauery { 661a3702c1fSVernon Mauery ret = mtm.disablePidControlService(true); 662a3702c1fSVernon Mauery if (ret < 0) 663a3702c1fSVernon Mauery { 6645e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 665a3702c1fSVernon Mauery } 666a3702c1fSVernon Mauery mtm.revertFanPWM = true; 667a3702c1fSVernon Mauery } 668a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 66990eb7876SAlex Schendel std::string pwmName, fanPwmInstancePath; 6704180cfe9SAlex Schendel if (!findPwmName(ctx, instance + 1, pwmName)) 67190eb7876SAlex Schendel { 67290eb7876SAlex Schendel pwmName = "Pwm_" + std::to_string(instance + 1); 67390eb7876SAlex Schendel } 67490eb7876SAlex Schendel fanPwmInstancePath = fanPwmPath + pwmName; 675b37abfb2SPatrick Williams ret = mtm.setProperty(fanService, fanPwmInstancePath, 676b37abfb2SPatrick Williams fanIntf, "Value", 677b37abfb2SPatrick Williams static_cast<double>(pwmValue)); 678a3702c1fSVernon Mauery if (ret < 0) 679a3702c1fSVernon Mauery { 6805e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 681a3702c1fSVernon Mauery } 682a3702c1fSVernon Mauery } 683a3702c1fSVernon Mauery break; 684a3702c1fSVernon Mauery default: 685a3702c1fSVernon Mauery { 6865e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 687a3702c1fSVernon Mauery } 688a3702c1fSVernon Mauery } 689a3702c1fSVernon Mauery } 690a3702c1fSVernon Mauery break; 691d872a4a4SAyushi Smriti case SmSignalSet::smSpeaker: 692d872a4a4SAyushi Smriti { 6934180cfe9SAlex Schendel lg2::info("Performing Speaker SmActionSet", "ACTION", lg2::dec, 6944180cfe9SAlex Schendel static_cast<uint8_t>(action)); 695d872a4a4SAyushi Smriti switch (action) 696d872a4a4SAyushi Smriti { 697d872a4a4SAyushi Smriti case SmActionSet::forceAsserted: 698d872a4a4SAyushi Smriti { 699d872a4a4SAyushi Smriti char beepDevName[] = "/dev/input/event0"; 700d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 701d872a4a4SAyushi Smriti { 7024180cfe9SAlex Schendel lg2::info("mtm beep device is opened already!"); 703d872a4a4SAyushi Smriti // returning success as already beep is in progress 704d872a4a4SAyushi Smriti return ipmi::response(retCode); 705d872a4a4SAyushi Smriti } 706d872a4a4SAyushi Smriti 707b37abfb2SPatrick Williams if ((mtm.mtmTestBeepFd = ::open(beepDevName, 708b37abfb2SPatrick Williams O_RDWR | O_CLOEXEC)) < 0) 709d872a4a4SAyushi Smriti { 7104180cfe9SAlex Schendel lg2::error("Failed to open input device"); 711d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 712d872a4a4SAyushi Smriti } 713d872a4a4SAyushi Smriti 714d872a4a4SAyushi Smriti struct input_event event; 715d872a4a4SAyushi Smriti event.type = EV_SND; 716d872a4a4SAyushi Smriti event.code = SND_TONE; 717d872a4a4SAyushi Smriti event.value = 2000; 718d872a4a4SAyushi Smriti 719d872a4a4SAyushi Smriti if (::write(mtm.mtmTestBeepFd, &event, 720d872a4a4SAyushi Smriti sizeof(struct input_event)) != 721d872a4a4SAyushi Smriti sizeof(struct input_event)) 722d872a4a4SAyushi Smriti { 7234180cfe9SAlex Schendel lg2::error("Failed to write a tone sound event"); 724d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 725d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 726d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 727d872a4a4SAyushi Smriti } 728d872a4a4SAyushi Smriti mtm.revertTimer.start(revertTimeOut); 729d872a4a4SAyushi Smriti } 730d872a4a4SAyushi Smriti break; 731d872a4a4SAyushi Smriti case SmActionSet::revert: 732d872a4a4SAyushi Smriti case SmActionSet::forceDeasserted: 733d872a4a4SAyushi Smriti { 734d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 735d872a4a4SAyushi Smriti { 736d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 737d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 738d872a4a4SAyushi Smriti } 739d872a4a4SAyushi Smriti } 740d872a4a4SAyushi Smriti break; 741d872a4a4SAyushi Smriti default: 742d872a4a4SAyushi Smriti { 743d872a4a4SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 744d872a4a4SAyushi Smriti } 745d872a4a4SAyushi Smriti } 746d872a4a4SAyushi Smriti } 747d872a4a4SAyushi Smriti break; 7483594c6d6SRichard Marian Thomaiyar case SmSignalSet::smDiskFaultLed: 7493594c6d6SRichard Marian Thomaiyar { 7503594c6d6SRichard Marian Thomaiyar boost::system::error_code ec; 7513594c6d6SRichard Marian Thomaiyar using objPaths = std::vector<std::string>; 7523594c6d6SRichard Marian Thomaiyar std::string driveBasePath = 7533594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/inventory/item/drive/"; 7543594c6d6SRichard Marian Thomaiyar static constexpr const char* driveLedIntf = 7553594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.Led.Group"; 7563594c6d6SRichard Marian Thomaiyar static constexpr const char* hsbpService = 7573594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.HsbpManager"; 7583594c6d6SRichard Marian Thomaiyar 7593594c6d6SRichard Marian Thomaiyar auto driveList = ctx->bus->yield_method_call<objPaths>( 7603594c6d6SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 7613594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 7623594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 7633594c6d6SRichard Marian Thomaiyar driveBasePath, 0, std::array<const char*, 1>{driveLedIntf}); 7643594c6d6SRichard Marian Thomaiyar if (ec) 7653594c6d6SRichard Marian Thomaiyar { 7664180cfe9SAlex Schendel lg2::error("Failed to query HSBP drive sub tree objects"); 7673594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 7683594c6d6SRichard Marian Thomaiyar } 769b37abfb2SPatrick Williams std::string driveObjPath = driveBasePath + "Drive_" + 770b37abfb2SPatrick Williams std::to_string(instance + 1); 7713594c6d6SRichard Marian Thomaiyar if (std::find(driveList.begin(), driveList.end(), driveObjPath) == 7723594c6d6SRichard Marian Thomaiyar driveList.end()) 7733594c6d6SRichard Marian Thomaiyar { 7743594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 7753594c6d6SRichard Marian Thomaiyar } 7763594c6d6SRichard Marian Thomaiyar bool driveLedState = false; 7773594c6d6SRichard Marian Thomaiyar switch (action) 7783594c6d6SRichard Marian Thomaiyar { 7793594c6d6SRichard Marian Thomaiyar case SmActionSet::forceAsserted: 7803594c6d6SRichard Marian Thomaiyar { 7813594c6d6SRichard Marian Thomaiyar driveLedState = true; 7823594c6d6SRichard Marian Thomaiyar } 7833594c6d6SRichard Marian Thomaiyar break; 7843594c6d6SRichard Marian Thomaiyar case SmActionSet::revert: 7853594c6d6SRichard Marian Thomaiyar { 7863594c6d6SRichard Marian Thomaiyar driveLedState = false; 7873594c6d6SRichard Marian Thomaiyar } 7883594c6d6SRichard Marian Thomaiyar break; 7893594c6d6SRichard Marian Thomaiyar case SmActionSet::forceDeasserted: 7903594c6d6SRichard Marian Thomaiyar { 7913594c6d6SRichard Marian Thomaiyar driveLedState = false; 7923594c6d6SRichard Marian Thomaiyar } 7933594c6d6SRichard Marian Thomaiyar break; 7943594c6d6SRichard Marian Thomaiyar default: 7953594c6d6SRichard Marian Thomaiyar { 7963594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 7973594c6d6SRichard Marian Thomaiyar } 7983594c6d6SRichard Marian Thomaiyar } 7993594c6d6SRichard Marian Thomaiyar ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf, 8003594c6d6SRichard Marian Thomaiyar "Asserted", driveLedState); 8013594c6d6SRichard Marian Thomaiyar if (ret < 0) 8023594c6d6SRichard Marian Thomaiyar { 8033594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 8043594c6d6SRichard Marian Thomaiyar } 8053594c6d6SRichard Marian Thomaiyar } 8063594c6d6SRichard Marian Thomaiyar break; 807a3702c1fSVernon Mauery default: 808a3702c1fSVernon Mauery { 8095e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 810a3702c1fSVernon Mauery } 811a3702c1fSVernon Mauery } 8124cc10159SRichard Marian Thomaiyar if (retCode == ccSuccess) 8134cc10159SRichard Marian Thomaiyar { 814357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 8154cc10159SRichard Marian Thomaiyar } 8165e3bf557SAyushi Smriti return ipmi::response(retCode); 817a3702c1fSVernon Mauery } 818a3702c1fSVernon Mauery 819357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved, 820666dd01cSRichard Marian Thomaiyar const std::array<char, 5>& intentionalSignature) 821666dd01cSRichard Marian Thomaiyar { 822e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM keep alive command only in 823e0511e5fSAyushi Smriti // manfacturing mode 824e0511e5fSAyushi Smriti 825666dd01cSRichard Marian Thomaiyar constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'}; 826666dd01cSRichard Marian Thomaiyar if (intentionalSignature != signatureOk || reserved != 0) 827666dd01cSRichard Marian Thomaiyar { 828666dd01cSRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 829666dd01cSRichard Marian Thomaiyar } 830357ddc74SRichard Marian Thomaiyar return ipmi::response(resetMtmTimer(ctx)); 831666dd01cSRichard Marian Thomaiyar } 832666dd01cSRichard Marian Thomaiyar 833e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd) 834e0511e5fSAyushi Smriti { 835e0511e5fSAyushi Smriti return (netFn << 8) | cmd; 836e0511e5fSAyushi Smriti } 837e0511e5fSAyushi Smriti 83885feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request) 83985feb130SYong Li { 840e0511e5fSAyushi Smriti // Restricted commands, must be executed only in Manufacturing mode 841e0511e5fSAyushi Smriti switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd)) 84285feb130SYong Li { 84380d4d5f9SMatt Simmering // i2c controller write read command needs additional checking 844e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead): 84585feb130SYong Li if (request->payload.size() > 4) 84685feb130SYong Li { 847ae13ac62SRichard Marian Thomaiyar // Allow write data count > 1 only in Special mode 848ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 84985feb130SYong Li { 85085feb130SYong Li return ipmi::ccInsufficientPrivilege; 85185feb130SYong Li } 85285feb130SYong Li } 8532d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 854e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 855e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetSmSignal): 856e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 857e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetSmSignal): 858e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 859e0511e5fSAyushi Smriti ipmi::intel::general::cmdMtmKeepAlive): 860e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 861e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetManufacturingData): 862e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 863e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetManufacturingData): 86427d2356eSVernon Mauery case makeCmdKey(ipmi::intel::netFnGeneral, 86527d2356eSVernon Mauery ipmi::intel::general::cmdSetFITcLayout): 86606584cd0SArun P. Mohanan case makeCmdKey(ipmi::netFnOemOne, 86706584cd0SArun P. Mohanan ipmi::intel::general::cmdMTMBMCFeatureControl): 868e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData): 8699a13daaeSAppaRao Puli case makeCmdKey(ipmi::netFnOemTwo, ipmi::intel::platform::cmdClearCMOS): 87085feb130SYong Li 871ae13ac62SRichard Marian Thomaiyar // Check for Special mode 872ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 873e0511e5fSAyushi Smriti { 874e0511e5fSAyushi Smriti return ipmi::ccInvalidCommand; 875e0511e5fSAyushi Smriti } 8762d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 8772d4a0198Sjayaprakash Mutyala case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry): 8782d4a0198Sjayaprakash Mutyala { 8792d4a0198Sjayaprakash Mutyala return ipmi::ccInvalidCommand; 8802d4a0198Sjayaprakash Mutyala } 881e0511e5fSAyushi Smriti } 88285feb130SYong Li return ipmi::ccSuccess; 88385feb130SYong Li } 88485feb130SYong Li 8851f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6; 8861f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3; 8871f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName = 8881f0839c2SRichard Marian Thomaiyar "/var/sofs/factory-settings/network/mac/eth"; 8891f0839c2SRichard Marian Thomaiyar 890097497fbSAlex Schendel bool findFruDevice(ipmi::Context::ptr& ctx, uint64_t& macOffset, 891ad129c68SZhikui Ren uint64_t& busNum, uint64_t& address) 892ad129c68SZhikui Ren { 893097497fbSAlex Schendel boost::system::error_code ec{}; 894097497fbSAlex Schendel ObjectValueTree obj; 895ad129c68SZhikui Ren 896ad129c68SZhikui Ren // GetAll the objects under service FruDevice 897097497fbSAlex Schendel ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager", 898097497fbSAlex Schendel "/xyz/openbmc_project/inventory", obj); 899ad129c68SZhikui Ren if (ec) 900ad129c68SZhikui Ren { 9014180cfe9SAlex Schendel lg2::error("GetManagedObjects failed", "ERROR", ec.message().c_str()); 902ad129c68SZhikui Ren return false; 903ad129c68SZhikui Ren } 904ad129c68SZhikui Ren 905ad129c68SZhikui Ren for (const auto& [path, fru] : obj) 906ad129c68SZhikui Ren { 907ad129c68SZhikui Ren for (const auto& [intf, propMap] : fru) 908ad129c68SZhikui Ren { 909ad129c68SZhikui Ren if (intf == "xyz.openbmc_project.Inventory.Item.Board.Motherboard") 910ad129c68SZhikui Ren { 911ad129c68SZhikui Ren auto findBus = propMap.find("FruBus"); 912ad129c68SZhikui Ren auto findAddress = propMap.find("FruAddress"); 913ad129c68SZhikui Ren auto findMacOffset = propMap.find("MacOffset"); 914ad129c68SZhikui Ren if (findBus == propMap.end() || findAddress == propMap.end() || 915ad129c68SZhikui Ren findMacOffset == propMap.end()) 916ad129c68SZhikui Ren { 917ad129c68SZhikui Ren continue; 918ad129c68SZhikui Ren } 919ad129c68SZhikui Ren 920ad129c68SZhikui Ren auto fruBus = std::get_if<uint64_t>(&findBus->second); 921ad129c68SZhikui Ren auto fruAddress = std::get_if<uint64_t>(&findAddress->second); 922ad129c68SZhikui Ren auto macFruOffset = 923ad129c68SZhikui Ren std::get_if<uint64_t>(&findMacOffset->second); 924ad129c68SZhikui Ren if (!fruBus || !fruAddress || !macFruOffset) 925ad129c68SZhikui Ren { 9264180cfe9SAlex Schendel lg2::info("ERROR: MotherBoard FRU config data type " 9274180cfe9SAlex Schendel "invalid, not used"); 928ad129c68SZhikui Ren return false; 929ad129c68SZhikui Ren } 930ad129c68SZhikui Ren busNum = *fruBus; 931ad129c68SZhikui Ren address = *fruAddress; 932ad129c68SZhikui Ren macOffset = *macFruOffset; 933ad129c68SZhikui Ren return true; 934ad129c68SZhikui Ren } 935ad129c68SZhikui Ren } 936ad129c68SZhikui Ren } 937ad129c68SZhikui Ren return false; 938ad129c68SZhikui Ren } 939ad129c68SZhikui Ren 94098fa87e6SZhikui Ren static constexpr uint64_t fruEnd = 0xff; 94198fa87e6SZhikui Ren // write rolls over within current page, need to keep mac within a page 94298fa87e6SZhikui Ren static constexpr uint64_t fruPageSize = 0x8; 94398fa87e6SZhikui Ren // MAC record struct: HEADER, MAC DATA, CheckSum 94498fa87e6SZhikui Ren static constexpr uint64_t macRecordSize = maxEthSize + 2; 94598fa87e6SZhikui Ren static_assert(fruPageSize >= macRecordSize, 94698fa87e6SZhikui Ren "macRecordSize greater than eeprom page size"); 94798fa87e6SZhikui Ren static constexpr uint8_t macHeader = 0x40; 94898fa87e6SZhikui Ren // Calculate new checksum for fru info area 94998fa87e6SZhikui Ren static uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter, 95098fa87e6SZhikui Ren std::vector<uint8_t>::const_iterator end) 95198fa87e6SZhikui Ren { 95298fa87e6SZhikui Ren constexpr int checksumMod = 256; 95398fa87e6SZhikui Ren uint8_t sum = std::accumulate(iter, end, static_cast<uint8_t>(0)); 95498fa87e6SZhikui Ren return (checksumMod - sum) % checksumMod; 95598fa87e6SZhikui Ren } 95698fa87e6SZhikui Ren 957ad129c68SZhikui Ren bool readMacFromFru(ipmi::Context::ptr ctx, uint8_t macIndex, 958ad129c68SZhikui Ren std::array<uint8_t, maxEthSize>& ethData) 959ad129c68SZhikui Ren { 960ad129c68SZhikui Ren uint64_t macOffset = fruEnd; 961ad129c68SZhikui Ren uint64_t fruBus = 0; 962ad129c68SZhikui Ren uint64_t fruAddress = 0; 963ad129c68SZhikui Ren 964097497fbSAlex Schendel if (findFruDevice(ctx, macOffset, fruBus, fruAddress)) 965ad129c68SZhikui Ren { 9664180cfe9SAlex Schendel lg2::info("Found mac fru", "BUS", lg2::dec, 9674180cfe9SAlex Schendel static_cast<uint8_t>(fruBus), "ADDRESS", lg2::dec, 9684180cfe9SAlex Schendel static_cast<uint8_t>(fruAddress)); 969ad129c68SZhikui Ren 97098fa87e6SZhikui Ren if (macOffset % fruPageSize) 97198fa87e6SZhikui Ren { 97298fa87e6SZhikui Ren macOffset = (macOffset / fruPageSize + 1) * fruPageSize; 97398fa87e6SZhikui Ren } 97498fa87e6SZhikui Ren macOffset += macIndex * fruPageSize; 97598fa87e6SZhikui Ren if ((macOffset + macRecordSize) > fruEnd) 976ad129c68SZhikui Ren { 9774180cfe9SAlex Schendel lg2::error("ERROR: read fru mac failed, offset invalid"); 978ad129c68SZhikui Ren return false; 979ad129c68SZhikui Ren } 980ad129c68SZhikui Ren std::vector<uint8_t> writeData; 98198fa87e6SZhikui Ren writeData.push_back(static_cast<uint8_t>(macOffset)); 98298fa87e6SZhikui Ren std::vector<uint8_t> readBuf(macRecordSize); 983ad129c68SZhikui Ren std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus); 984b37abfb2SPatrick Williams ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, 985b37abfb2SPatrick Williams readBuf); 986ad129c68SZhikui Ren if (retI2C == ipmi::ccSuccess) 987ad129c68SZhikui Ren { 98898fa87e6SZhikui Ren uint8_t cs = calculateChecksum(readBuf.cbegin(), readBuf.cend()); 98998fa87e6SZhikui Ren if (cs == 0) 99098fa87e6SZhikui Ren { 99198fa87e6SZhikui Ren std::copy(++readBuf.begin(), --readBuf.end(), ethData.data()); 992ad129c68SZhikui Ren return true; 993ad129c68SZhikui Ren } 994ad129c68SZhikui Ren } 99598fa87e6SZhikui Ren } 996ad129c68SZhikui Ren return false; 997ad129c68SZhikui Ren } 998ad129c68SZhikui Ren 999ad129c68SZhikui Ren ipmi::Cc writeMacToFru(ipmi::Context::ptr ctx, uint8_t macIndex, 1000ad129c68SZhikui Ren std::array<uint8_t, maxEthSize>& ethData) 1001ad129c68SZhikui Ren { 1002ad129c68SZhikui Ren uint64_t macOffset = fruEnd; 1003ad129c68SZhikui Ren uint64_t fruBus = 0; 1004ad129c68SZhikui Ren uint64_t fruAddress = 0; 1005ad129c68SZhikui Ren 1006097497fbSAlex Schendel if (findFruDevice(ctx, macOffset, fruBus, fruAddress)) 1007ad129c68SZhikui Ren { 10084180cfe9SAlex Schendel lg2::info("Found mac fru", "BUS", lg2::dec, 10094180cfe9SAlex Schendel static_cast<uint8_t>(fruBus), "ADDRESS", lg2::dec, 10104180cfe9SAlex Schendel static_cast<uint8_t>(fruAddress)); 1011ad129c68SZhikui Ren 101298fa87e6SZhikui Ren if (macOffset % fruPageSize) 101398fa87e6SZhikui Ren { 101498fa87e6SZhikui Ren macOffset = (macOffset / fruPageSize + 1) * fruPageSize; 101598fa87e6SZhikui Ren } 101698fa87e6SZhikui Ren macOffset += macIndex * fruPageSize; 101798fa87e6SZhikui Ren if ((macOffset + macRecordSize) > fruEnd) 1018ad129c68SZhikui Ren { 10194180cfe9SAlex Schendel lg2::error("ERROR: write mac fru failed, offset invalid."); 1020ad129c68SZhikui Ren return ipmi::ccParmOutOfRange; 1021ad129c68SZhikui Ren } 1022ad129c68SZhikui Ren std::vector<uint8_t> writeData; 102398fa87e6SZhikui Ren writeData.reserve(macRecordSize + 1); // include start location 102498fa87e6SZhikui Ren writeData.push_back(static_cast<uint8_t>(macOffset)); 102598fa87e6SZhikui Ren writeData.push_back(macHeader); 1026ad129c68SZhikui Ren std::for_each(ethData.cbegin(), ethData.cend(), 1027ad129c68SZhikui Ren [&](uint8_t i) { writeData.push_back(i); }); 1028b37abfb2SPatrick Williams uint8_t macCheckSum = calculateChecksum(++writeData.cbegin(), 1029b37abfb2SPatrick Williams writeData.cend()); 103098fa87e6SZhikui Ren writeData.push_back(macCheckSum); 1031ad129c68SZhikui Ren 1032ad129c68SZhikui Ren std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus); 1033ad129c68SZhikui Ren std::vector<uint8_t> readBuf; 1034b37abfb2SPatrick Williams ipmi::Cc ret = ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, 1035b37abfb2SPatrick Williams readBuf); 103698fa87e6SZhikui Ren 10370408e79eSZhikui Ren // prepare for read to detect chip is write protected 10380408e79eSZhikui Ren writeData.resize(1); 10390408e79eSZhikui Ren readBuf.resize(maxEthSize + 1); // include macHeader 10400408e79eSZhikui Ren 1041ad129c68SZhikui Ren switch (ret) 1042ad129c68SZhikui Ren { 1043ad129c68SZhikui Ren case ipmi::ccSuccess: 104498fa87e6SZhikui Ren // Wait for internal write cycle to complete 104598fa87e6SZhikui Ren // example: ATMEL 24c0x chip has Twr spec as 5ms 104698fa87e6SZhikui Ren 104798fa87e6SZhikui Ren // Ideally we want yield wait, but currently following code 104898fa87e6SZhikui Ren // crash with "thread not supported" 104998fa87e6SZhikui Ren // boost::asio::deadline_timer timer( 105098fa87e6SZhikui Ren // boost::asio::get_associated_executor(ctx->yield), 105198fa87e6SZhikui Ren // boost::posix_time::seconds(1)); 105298fa87e6SZhikui Ren // timer.async_wait(ctx->yield); 105398fa87e6SZhikui Ren // use usleep as temp WA 105498fa87e6SZhikui Ren usleep(5000); 105598fa87e6SZhikui Ren if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, 105698fa87e6SZhikui Ren readBuf) == ipmi::ccSuccess) 1057ad129c68SZhikui Ren { 1058ad129c68SZhikui Ren if (std::equal(ethData.begin(), ethData.end(), 105998fa87e6SZhikui Ren ++readBuf.begin())) // skip macHeader 1060ad129c68SZhikui Ren { 1061ad129c68SZhikui Ren return ipmi::ccSuccess; 1062ad129c68SZhikui Ren } 10634180cfe9SAlex Schendel lg2::info("INFO: write mac fru verify failed, fru may be " 10644180cfe9SAlex Schendel "write protected."); 1065ad129c68SZhikui Ren } 1066ad129c68SZhikui Ren return ipmi::ccCommandNotAvailable; 10670408e79eSZhikui Ren default: 10680408e79eSZhikui Ren if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, 10690408e79eSZhikui Ren readBuf) == ipmi::ccSuccess) 10700408e79eSZhikui Ren { 10714180cfe9SAlex Schendel lg2::info("INFO: write mac fru failed, but successfully " 10724180cfe9SAlex Schendel "read from fru, fru may be write protected."); 10730408e79eSZhikui Ren return ipmi::ccCommandNotAvailable; 10740408e79eSZhikui Ren } 10750408e79eSZhikui Ren else // assume failure is due to no eeprom on board 10760408e79eSZhikui Ren { 10774180cfe9SAlex Schendel lg2::error("ERROR: write mac fru failed, assume no eeprom " 10784180cfe9SAlex Schendel "is available."); 10790408e79eSZhikui Ren } 1080ad129c68SZhikui Ren break; 1081ad129c68SZhikui Ren } 1082ad129c68SZhikui Ren } 1083ad129c68SZhikui Ren // no FRU eeprom found 1084ad129c68SZhikui Ren return ipmi::ccDestinationUnavailable; 1085ad129c68SZhikui Ren } 1086ad129c68SZhikui Ren 1087357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType, 10881f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData) 10891f0839c2SRichard Marian Thomaiyar { 1090ad129c68SZhikui Ren // mfg filter logic will restrict this command executing only in mfg 1091ad129c68SZhikui Ren // mode. 10921f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 10931f0839c2SRichard Marian Thomaiyar { 10941f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 10951f0839c2SRichard Marian Thomaiyar } 10961f0839c2SRichard Marian Thomaiyar 10971f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 10981f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 1099ad129c68SZhikui Ren 1100ad129c68SZhikui Ren ipmi::Cc ret = writeMacToFru(ctx, dataType, ethData); 1101ad129c68SZhikui Ren if (ret != ipmi::ccDestinationUnavailable) 1102ad129c68SZhikui Ren { 1103ad129c68SZhikui Ren resetMtmTimer(ctx); 1104ad129c68SZhikui Ren return response(ret); 1105ad129c68SZhikui Ren } 1106ad129c68SZhikui Ren 11071f0839c2SRichard Marian Thomaiyar constexpr uint8_t ethAddrStrSize = 11081f0839c2SRichard Marian Thomaiyar 19; // XX:XX:XX:XX:XX:XX + \n + null termination; 11091f0839c2SRichard Marian Thomaiyar std::vector<uint8_t> buff(ethAddrStrSize); 11101f0839c2SRichard Marian Thomaiyar std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize, 11111f0839c2SRichard Marian Thomaiyar "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0), 11121f0839c2SRichard Marian Thomaiyar ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4), 11131f0839c2SRichard Marian Thomaiyar ethData.at(5)); 11141f0839c2SRichard Marian Thomaiyar std::ofstream oEthFile(factoryEthAddrBaseFileName + 11151f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 11161f0839c2SRichard Marian Thomaiyar std::ofstream::out); 11171f0839c2SRichard Marian Thomaiyar if (!oEthFile.good()) 11181f0839c2SRichard Marian Thomaiyar { 11191f0839c2SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 11201f0839c2SRichard Marian Thomaiyar } 11211f0839c2SRichard Marian Thomaiyar 11221f0839c2SRichard Marian Thomaiyar oEthFile << reinterpret_cast<char*>(buff.data()); 11236d83e4eeSJohnathan Mantey oEthFile.flush(); 11241f0839c2SRichard Marian Thomaiyar oEthFile.close(); 11251f0839c2SRichard Marian Thomaiyar 1126357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 11271f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(); 11281f0839c2SRichard Marian Thomaiyar } 11291f0839c2SRichard Marian Thomaiyar 11301f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>> 1131357ddc74SRichard Marian Thomaiyar getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType) 11321f0839c2SRichard Marian Thomaiyar { 1133ad129c68SZhikui Ren // mfg filter logic will restrict this command executing only in mfg 1134ad129c68SZhikui Ren // mode. 11351f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 11361f0839c2SRichard Marian Thomaiyar { 11371f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 11381f0839c2SRichard Marian Thomaiyar } 11391f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData{0}; 11401f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 11411f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 11421f0839c2SRichard Marian Thomaiyar 11431f0839c2SRichard Marian Thomaiyar std::ifstream iEthFile(factoryEthAddrBaseFileName + 11441f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 11451f0839c2SRichard Marian Thomaiyar std::ifstream::in); 11461f0839c2SRichard Marian Thomaiyar if (!iEthFile.good()) 11471f0839c2SRichard Marian Thomaiyar { 1148ad129c68SZhikui Ren if (readMacFromFru(ctx, dataType, ethData)) 1149ad129c68SZhikui Ren { 1150ad129c68SZhikui Ren resetMtmTimer(ctx); 1151ad129c68SZhikui Ren return ipmi::responseSuccess(validData, ethData); 1152ad129c68SZhikui Ren } 11531f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(invalidData, ethData); 11541f0839c2SRichard Marian Thomaiyar } 11551f0839c2SRichard Marian Thomaiyar std::string ethStr; 11561f0839c2SRichard Marian Thomaiyar iEthFile >> ethStr; 11571f0839c2SRichard Marian Thomaiyar uint8_t* data = ethData.data(); 11581f0839c2SRichard Marian Thomaiyar std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 11591f0839c2SRichard Marian Thomaiyar data, (data + 1), (data + 2), (data + 3), (data + 4), 11601f0839c2SRichard Marian Thomaiyar (data + 5)); 11611f0839c2SRichard Marian Thomaiyar 1162357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 11631f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(validData, ethData); 11641f0839c2SRichard Marian Thomaiyar } 11651f0839c2SRichard Marian Thomaiyar 116680d4d5f9SMatt Simmering /** @brief implements slot controller write read IPMI command which can be used 1167ad129c68SZhikui Ren * for low-level I2C/SMBus write, read or write-read access for PCIE slots 11687acb2d27SV-Sanjana * @param reserved - skip 3 bit 11697acb2d27SV-Sanjana * @param muxType - mux type 1170f267a67dSYong Li * @param addressType - address type 1171f267a67dSYong Li * @param bbSlotNum - baseboard slot number 1172f267a67dSYong Li * @param riserSlotNum - riser slot number 1173f267a67dSYong Li * @param reserved2 - skip 2 bit 117480d4d5f9SMatt Simmering * @param targetAddr - target address 1175f267a67dSYong Li * @param readCount - number of bytes to be read 1176f267a67dSYong Li * @param writeData - data to be written 1177f267a67dSYong Li * 1178f267a67dSYong Li * @returns IPMI completion code plus response data 1179f267a67dSYong Li */ 11807acb2d27SV-Sanjana 118180d4d5f9SMatt Simmering ipmi::RspType<std::vector<uint8_t>> appSlotI2CControllerWriteRead( 11827acb2d27SV-Sanjana uint3_t reserved, uint3_t muxType, uint2_t addressType, uint3_t bbSlotNum, 118380d4d5f9SMatt Simmering uint3_t riserSlotNum, uint2_t reserved2, uint8_t targetAddr, 1184f267a67dSYong Li uint8_t readCount, std::vector<uint8_t> writeData) 1185f267a67dSYong Li { 1186fc3bc381SVernon Mauery if (reserved || reserved2) 1187fc3bc381SVernon Mauery { 1188fc3bc381SVernon Mauery return ipmi::responseInvalidFieldRequest(); 1189fc3bc381SVernon Mauery } 1190f267a67dSYong Li const size_t writeCount = writeData.size(); 1191f267a67dSYong Li std::string i2cBus; 1192f267a67dSYong Li if (addressType == slotAddressTypeBus) 1193f267a67dSYong Li { 11947acb2d27SV-Sanjana std::string path = "/dev/i2c-mux/"; 11957acb2d27SV-Sanjana if (muxType == bbRiserMux) 11967acb2d27SV-Sanjana { 11977acb2d27SV-Sanjana path += "Riser_" + std::to_string(static_cast<uint8_t>(bbSlotNum)) + 1198f267a67dSYong Li "_Mux/Pcie_Slot_" + 1199f267a67dSYong Li std::to_string(static_cast<uint8_t>(riserSlotNum)); 12007acb2d27SV-Sanjana } 12017acb2d27SV-Sanjana else if (muxType == leftRiserMux) 12027acb2d27SV-Sanjana { 12037acb2d27SV-Sanjana path += "Left_Riser_Mux/Slot_" + 12047acb2d27SV-Sanjana std::to_string(static_cast<uint8_t>(riserSlotNum)); 12057acb2d27SV-Sanjana } 12067acb2d27SV-Sanjana else if (muxType == rightRiserMux) 12077acb2d27SV-Sanjana { 12087acb2d27SV-Sanjana path += "Right_Riser_Mux/Slot_" + 12097acb2d27SV-Sanjana std::to_string(static_cast<uint8_t>(riserSlotNum)); 12107acb2d27SV-Sanjana } 12117acb2d27SV-Sanjana else if (muxType == pcieMux) 12127acb2d27SV-Sanjana { 12137acb2d27SV-Sanjana path += "PCIe_Mux/Slot_" + 12147acb2d27SV-Sanjana std::to_string(static_cast<uint8_t>(riserSlotNum)); 12157acb2d27SV-Sanjana } 12167acb2d27SV-Sanjana else if (muxType == hsbpMux) 12177acb2d27SV-Sanjana { 12187acb2d27SV-Sanjana path += "HSBP_Mux/Slot" + 12197acb2d27SV-Sanjana std::to_string(static_cast<uint8_t>(riserSlotNum)); 12207acb2d27SV-Sanjana } 12217acb2d27SV-Sanjana phosphor::logging::log<phosphor::logging::level::DEBUG>( 12227acb2d27SV-Sanjana ("Path is: " + path).c_str()); 1223f267a67dSYong Li if (std::filesystem::exists(path) && std::filesystem::is_symlink(path)) 1224f267a67dSYong Li { 1225f267a67dSYong Li i2cBus = std::filesystem::read_symlink(path); 1226f267a67dSYong Li } 1227f267a67dSYong Li else 1228f267a67dSYong Li { 122980d4d5f9SMatt Simmering lg2::error("Controller write read command: Cannot get BusID"); 1230f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 1231f267a67dSYong Li } 1232f267a67dSYong Li } 1233f267a67dSYong Li else if (addressType == slotAddressTypeUniqueid) 1234f267a67dSYong Li { 1235f267a67dSYong Li i2cBus = "/dev/i2c-" + 1236f267a67dSYong Li std::to_string(static_cast<uint8_t>(bbSlotNum) | 1237f267a67dSYong Li (static_cast<uint8_t>(riserSlotNum) << 3)); 1238f267a67dSYong Li } 1239f267a67dSYong Li else 1240f267a67dSYong Li { 124180d4d5f9SMatt Simmering lg2::error("Controller write read command: invalid request"); 1242f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 1243f267a67dSYong Li } 1244f267a67dSYong Li 1245ad129c68SZhikui Ren // Allow single byte write as it is offset byte to read the data, rest 1246ad129c68SZhikui Ren // allow only in Special mode. 1247f267a67dSYong Li if (writeCount > 1) 1248f267a67dSYong Li { 1249ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 1250f267a67dSYong Li { 1251f267a67dSYong Li return ipmi::responseInsufficientPrivilege(); 1252f267a67dSYong Li } 1253f267a67dSYong Li } 1254f267a67dSYong Li 1255f267a67dSYong Li if (readCount > slotI2CMaxReadSize) 1256f267a67dSYong Li { 125780d4d5f9SMatt Simmering lg2::error("Controller write read command: Read count exceeds limit"); 1258f267a67dSYong Li return ipmi::responseParmOutOfRange(); 1259f267a67dSYong Li } 1260f267a67dSYong Li 1261f267a67dSYong Li if (!readCount && !writeCount) 1262f267a67dSYong Li { 126380d4d5f9SMatt Simmering lg2::error("Controller write read command: Read & write count are 0"); 1264f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 1265f267a67dSYong Li } 1266f267a67dSYong Li 1267f267a67dSYong Li std::vector<uint8_t> readBuf(readCount); 1268f267a67dSYong Li 1269b37abfb2SPatrick Williams ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, targetAddr, writeData, 1270b37abfb2SPatrick Williams readBuf); 1271f267a67dSYong Li if (retI2C != ipmi::ccSuccess) 1272f267a67dSYong Li { 1273f267a67dSYong Li return ipmi::response(retI2C); 1274f267a67dSYong Li } 1275f267a67dSYong Li 1276f267a67dSYong Li return ipmi::responseSuccess(readBuf); 1277f267a67dSYong Li } 1278068b4f2cSYong Li 1279068b4f2cSYong Li ipmi::RspType<> clearCMOS() 1280068b4f2cSYong Li { 128180d4d5f9SMatt Simmering // There is an i2c device on bus 4, the target address is 0x38. Based on 1282ad129c68SZhikui Ren // the spec, writing 0x1 to address 0x61 on this device, will trigger 1283ad129c68SZhikui Ren // the clear CMOS action. 128480d4d5f9SMatt Simmering constexpr uint8_t targetAddr = 0x38; 1285068b4f2cSYong Li std::string i2cBus = "/dev/i2c-4"; 1286eaeb6cb0SYong Li std::vector<uint8_t> writeData = {0x61, 0x1}; 1287068b4f2cSYong Li std::vector<uint8_t> readBuf(0); 1288068b4f2cSYong Li 1289b37abfb2SPatrick Williams ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, targetAddr, writeData, 1290b37abfb2SPatrick Williams readBuf); 1291068b4f2cSYong Li return ipmi::response(retI2C); 1292068b4f2cSYong Li } 129327d2356eSVernon Mauery 129427d2356eSVernon Mauery ipmi::RspType<> setFITcLayout(uint32_t layout) 129527d2356eSVernon Mauery { 129627d2356eSVernon Mauery static constexpr const char* factoryFITcLayout = 129727d2356eSVernon Mauery "/var/sofs/factory-settings/layout/fitc"; 129827d2356eSVernon Mauery std::filesystem::path fitcDir = 129927d2356eSVernon Mauery std::filesystem::path(factoryFITcLayout).parent_path(); 130027d2356eSVernon Mauery std::error_code ec; 130127d2356eSVernon Mauery std::filesystem::create_directories(fitcDir, ec); 130227d2356eSVernon Mauery if (ec) 130327d2356eSVernon Mauery { 130427d2356eSVernon Mauery return ipmi::responseUnspecifiedError(); 130527d2356eSVernon Mauery } 130627d2356eSVernon Mauery try 130727d2356eSVernon Mauery { 130827d2356eSVernon Mauery std::ofstream file(factoryFITcLayout); 130927d2356eSVernon Mauery file << layout; 131027d2356eSVernon Mauery file.flush(); 131127d2356eSVernon Mauery file.close(); 131227d2356eSVernon Mauery } 131327d2356eSVernon Mauery catch (const std::exception& e) 131427d2356eSVernon Mauery { 131527d2356eSVernon Mauery return ipmi::responseUnspecifiedError(); 131627d2356eSVernon Mauery } 131727d2356eSVernon Mauery 131827d2356eSVernon Mauery return ipmi::responseSuccess(); 131927d2356eSVernon Mauery } 132027d2356eSVernon Mauery 132106584cd0SArun P. Mohanan static std::vector<std::string> 132206584cd0SArun P. Mohanan getMCTPServiceConfigPaths(ipmi::Context::ptr& ctx) 132306584cd0SArun P. Mohanan { 132406584cd0SArun P. Mohanan boost::system::error_code ec; 132506584cd0SArun P. Mohanan auto configPaths = ctx->bus->yield_method_call<std::vector<std::string>>( 132606584cd0SArun P. Mohanan ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 132706584cd0SArun P. Mohanan "/xyz/openbmc_project/object_mapper", 132806584cd0SArun P. Mohanan "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 132906584cd0SArun P. Mohanan "/xyz/openbmc_project/inventory/system/board", 2, 133006584cd0SArun P. Mohanan std::array<const char*, 1>{ 133106584cd0SArun P. Mohanan "xyz.openbmc_project.Configuration.MctpConfiguration"}); 133206584cd0SArun P. Mohanan if (ec) 133306584cd0SArun P. Mohanan { 133406584cd0SArun P. Mohanan throw std::runtime_error( 133506584cd0SArun P. Mohanan "Failed to query configuration sub tree objects"); 133606584cd0SArun P. Mohanan } 133706584cd0SArun P. Mohanan return configPaths; 133806584cd0SArun P. Mohanan } 133906584cd0SArun P. Mohanan 134006584cd0SArun P. Mohanan static ipmi::RspType<> startOrStopService(ipmi::Context::ptr& ctx, 134106584cd0SArun P. Mohanan const uint8_t enable, 13421fe485cdSANJALI RAY const std::string& serviceName, 13431fe485cdSANJALI RAY bool disableOrEnableUnitFiles = true) 134406584cd0SArun P. Mohanan { 134506584cd0SArun P. Mohanan constexpr bool runtimeOnly = false; 134606584cd0SArun P. Mohanan constexpr bool force = false; 134706584cd0SArun P. Mohanan 134806584cd0SArun P. Mohanan boost::system::error_code ec; 134906584cd0SArun P. Mohanan switch (enable) 135006584cd0SArun P. Mohanan { 135106584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::stop: 135206584cd0SArun P. Mohanan ctx->bus->yield_method_call(ctx->yield, ec, systemDService, 135306584cd0SArun P. Mohanan systemDObjPath, systemDMgrIntf, 135406584cd0SArun P. Mohanan "StopUnit", serviceName, "replace"); 135506584cd0SArun P. Mohanan break; 135606584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::start: 135706584cd0SArun P. Mohanan ctx->bus->yield_method_call(ctx->yield, ec, systemDService, 135806584cd0SArun P. Mohanan systemDObjPath, systemDMgrIntf, 135906584cd0SArun P. Mohanan "StartUnit", serviceName, "replace"); 136006584cd0SArun P. Mohanan break; 136106584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::disable: 13621fe485cdSANJALI RAY if (disableOrEnableUnitFiles == true) 13631fe485cdSANJALI RAY { 13641fe485cdSANJALI RAY ctx->bus->yield_method_call( 13651fe485cdSANJALI RAY ctx->yield, ec, systemDService, systemDObjPath, 13661fe485cdSANJALI RAY systemDMgrIntf, "DisableUnitFiles", 13671fe485cdSANJALI RAY std::array<const char*, 1>{serviceName.c_str()}, 13681fe485cdSANJALI RAY runtimeOnly); 13691fe485cdSANJALI RAY } 137006584cd0SArun P. Mohanan ctx->bus->yield_method_call( 137106584cd0SArun P. Mohanan ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf, 137206584cd0SArun P. Mohanan "MaskUnitFiles", 137306584cd0SArun P. Mohanan std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly, 137406584cd0SArun P. Mohanan force); 137506584cd0SArun P. Mohanan break; 137606584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::enable: 137706584cd0SArun P. Mohanan ctx->bus->yield_method_call( 137806584cd0SArun P. Mohanan ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf, 137906584cd0SArun P. Mohanan "UnmaskUnitFiles", 138006584cd0SArun P. Mohanan std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly); 13811fe485cdSANJALI RAY if (disableOrEnableUnitFiles == true) 13821fe485cdSANJALI RAY { 138306584cd0SArun P. Mohanan ctx->bus->yield_method_call( 13841fe485cdSANJALI RAY ctx->yield, ec, systemDService, systemDObjPath, 13851fe485cdSANJALI RAY systemDMgrIntf, "EnableUnitFiles", 13861fe485cdSANJALI RAY std::array<const char*, 1>{serviceName.c_str()}, 13871fe485cdSANJALI RAY runtimeOnly, force); 13881fe485cdSANJALI RAY } 138906584cd0SArun P. Mohanan break; 139006584cd0SArun P. Mohanan default: 13914180cfe9SAlex Schendel lg2::warning("ERROR: Invalid feature action selected", "ACTION", 13924180cfe9SAlex Schendel lg2::dec, enable); 139306584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 139406584cd0SArun P. Mohanan } 139506584cd0SArun P. Mohanan if (ec) 139606584cd0SArun P. Mohanan { 13974180cfe9SAlex Schendel lg2::warning("ERROR: Service start or stop failed", "SERVICE", 13984180cfe9SAlex Schendel serviceName.c_str()); 139906584cd0SArun P. Mohanan return ipmi::responseUnspecifiedError(); 140006584cd0SArun P. Mohanan } 140106584cd0SArun P. Mohanan return ipmi::responseSuccess(); 140206584cd0SArun P. Mohanan } 140306584cd0SArun P. Mohanan 140406584cd0SArun P. Mohanan static std::string getMCTPServiceName(const std::string& objectPath) 140506584cd0SArun P. Mohanan { 140606584cd0SArun P. Mohanan const auto serviceArgument = boost::algorithm::replace_all_copy( 140706584cd0SArun P. Mohanan boost::algorithm::replace_first_copy( 140806584cd0SArun P. Mohanan objectPath, "/xyz/openbmc_project/inventory/system/board/", ""), 140906584cd0SArun P. Mohanan "/", "_2f"); 1410b37abfb2SPatrick Williams std::string unitName = "xyz.openbmc_project.mctpd@" + serviceArgument + 1411b37abfb2SPatrick Williams ".service"; 141206584cd0SArun P. Mohanan return unitName; 141306584cd0SArun P. Mohanan } 141406584cd0SArun P. Mohanan 141506584cd0SArun P. Mohanan static ipmi::RspType<> handleMCTPFeature(ipmi::Context::ptr& ctx, 141606584cd0SArun P. Mohanan const uint8_t enable, 141706584cd0SArun P. Mohanan const std::string& binding) 141806584cd0SArun P. Mohanan { 141906584cd0SArun P. Mohanan std::vector<std::string> configPaths; 142006584cd0SArun P. Mohanan try 142106584cd0SArun P. Mohanan { 142206584cd0SArun P. Mohanan configPaths = getMCTPServiceConfigPaths(ctx); 142306584cd0SArun P. Mohanan } 142406584cd0SArun P. Mohanan catch (const std::exception& e) 142506584cd0SArun P. Mohanan { 14264180cfe9SAlex Schendel lg2::error(e.what()); 142706584cd0SArun P. Mohanan return ipmi::responseUnspecifiedError(); 142806584cd0SArun P. Mohanan } 142906584cd0SArun P. Mohanan 143006584cd0SArun P. Mohanan for (const auto& objectPath : configPaths) 143106584cd0SArun P. Mohanan { 1432b37abfb2SPatrick Williams const auto pos = objectPath.find_last_of('/'); 143306584cd0SArun P. Mohanan if (binding == objectPath.substr(pos + 1)) 143406584cd0SArun P. Mohanan { 143506584cd0SArun P. Mohanan return startOrStopService(ctx, enable, 14361fe485cdSANJALI RAY getMCTPServiceName(objectPath), false); 143706584cd0SArun P. Mohanan } 143806584cd0SArun P. Mohanan } 143906584cd0SArun P. Mohanan return ipmi::responseSuccess(); 144006584cd0SArun P. Mohanan } 144106584cd0SArun P. Mohanan 1442*97c30909SVasu V static bool isNum(const std::string& s) 1443*97c30909SVasu V { 1444*97c30909SVasu V if (s.empty()) 1445*97c30909SVasu V { 1446*97c30909SVasu V return false; 1447*97c30909SVasu V } 1448*97c30909SVasu V uint8_t busNumber; 1449*97c30909SVasu V const auto sEnd = s.data() + s.size(); 1450*97c30909SVasu V const auto& [ptr, ec] = std::from_chars(s.data(), sEnd, busNumber); 1451*97c30909SVasu V if (ec == std::errc() || ptr == sEnd) 1452*97c30909SVasu V { 1453*97c30909SVasu V return true; 1454*97c30909SVasu V } 1455*97c30909SVasu V return false; 1456*97c30909SVasu V } 1457*97c30909SVasu V 1458*97c30909SVasu V bool getBusNumFromPath(const std::string& path, std::string& busStr) 1459*97c30909SVasu V { 1460*97c30909SVasu V std::vector<std::string> parts; 1461*97c30909SVasu V boost::split(parts, path, boost::is_any_of("-")); 1462*97c30909SVasu V if (parts.size() == 2) 1463*97c30909SVasu V { 1464*97c30909SVasu V busStr = parts[1]; 1465*97c30909SVasu V if (isNum(busStr)) 1466*97c30909SVasu V { 1467*97c30909SVasu V return true; 1468*97c30909SVasu V } 1469*97c30909SVasu V } 1470*97c30909SVasu V return false; 1471*97c30909SVasu V } 1472*97c30909SVasu V 1473*97c30909SVasu V static ipmi::RspType<> muxSlotDisable(ipmi::Context::ptr& ctx, 1474*97c30909SVasu V std::string service, std::string muxName, 1475*97c30909SVasu V uint8_t action, uint8_t slotNum) 1476*97c30909SVasu V { 1477*97c30909SVasu V boost::system::error_code ec; 1478*97c30909SVasu V const std::filesystem::path muxSymlinkDirPath = 1479*97c30909SVasu V "/dev/i2c-mux/" + muxName + "/Slot_" + std::to_string(slotNum + 1); 1480*97c30909SVasu V if (!std::filesystem::is_symlink(muxSymlinkDirPath)) 1481*97c30909SVasu V { 1482*97c30909SVasu V return ipmi::responseInvalidFieldRequest(); 1483*97c30909SVasu V } 1484*97c30909SVasu V std::string linkPath = std::filesystem::read_symlink(muxSymlinkDirPath); 1485*97c30909SVasu V 1486*97c30909SVasu V std::string portNum; 1487*97c30909SVasu V if (!getBusNumFromPath(linkPath, portNum)) 1488*97c30909SVasu V { 1489*97c30909SVasu V return ipmi::responseInvalidFieldRequest(); 1490*97c30909SVasu V } 1491*97c30909SVasu V auto res = ctx->bus->yield_method_call<int>( 1492*97c30909SVasu V ctx->yield, ec, service, mctpObjPath, mctpBaseIntf, "SkipList", 1493*97c30909SVasu V std::vector<uint8_t>{action, static_cast<uint8_t>(std::stoi(portNum))}); 1494*97c30909SVasu V if (ec) 1495*97c30909SVasu V { 1496*97c30909SVasu V lg2::error("Failed to set mctp skiplist"); 1497*97c30909SVasu V return ipmi::responseUnspecifiedError(); 1498*97c30909SVasu V } 1499*97c30909SVasu V 1500*97c30909SVasu V if (!res) 1501*97c30909SVasu V { 1502*97c30909SVasu V return ipmi::responseResponseError(); 1503*97c30909SVasu V } 1504*97c30909SVasu V return ipmi::responseSuccess(); 1505*97c30909SVasu V } 1506*97c30909SVasu V 1507*97c30909SVasu V static ipmi::RspType<> handleMCTPSlotFeature(ipmi::Context::ptr& ctx, 1508*97c30909SVasu V const uint8_t enable, 1509*97c30909SVasu V const uint8_t featureArg) 1510*97c30909SVasu V { 1511*97c30909SVasu V uint8_t slotNum = (featureArg & slotNumMask); 1512*97c30909SVasu V switch ((featureArg & muxTypeMask) >> muxTypeShift) 1513*97c30909SVasu V { 1514*97c30909SVasu V case ipmi::SupportedFeatureMuxs::pcieMuxSlot: 1515*97c30909SVasu V return muxSlotDisable(ctx, mctpPcieSlotService, "PCIe_Mux", enable, 1516*97c30909SVasu V slotNum); 1517*97c30909SVasu V break; 1518*97c30909SVasu V case ipmi::SupportedFeatureMuxs::pcieMcioMuxSlot: 1519*97c30909SVasu V return muxSlotDisable(ctx, mctpPcieSlotService, "PCIe_MCIO_Mux", 1520*97c30909SVasu V enable, slotNum); 1521*97c30909SVasu V break; 1522*97c30909SVasu V case ipmi::SupportedFeatureMuxs::pcieM2EdSffMuxSlot: 1523*97c30909SVasu V return muxSlotDisable(ctx, mctpPcieSlotService, "M2_EDSFF_Mux", 1524*97c30909SVasu V enable, slotNum); 1525*97c30909SVasu V break; 1526*97c30909SVasu V case ipmi::SupportedFeatureMuxs::leftRaiserMuxSlot: 1527*97c30909SVasu V return muxSlotDisable(ctx, mctpPcieSlotService, "Left_Riser_Mux", 1528*97c30909SVasu V enable, slotNum); 1529*97c30909SVasu V break; 1530*97c30909SVasu V case ipmi::SupportedFeatureMuxs::rightRaiserMuxSlot: 1531*97c30909SVasu V return muxSlotDisable(ctx, mctpPcieSlotService, "Right_Riser_Mux", 1532*97c30909SVasu V enable, slotNum); 1533*97c30909SVasu V break; 1534*97c30909SVasu V case ipmi::SupportedFeatureMuxs::HsbpMuxSlot: 1535*97c30909SVasu V return muxSlotDisable(ctx, mctpHsbpService, "HSBP_Mux", enable, 1536*97c30909SVasu V slotNum); 1537*97c30909SVasu V break; 1538*97c30909SVasu V default: 1539*97c30909SVasu V lg2::warning("ERROR: Invalid Mux slot selected"); 1540*97c30909SVasu V return ipmi::responseInvalidFieldRequest(); 1541*97c30909SVasu V } 1542*97c30909SVasu V } 1543*97c30909SVasu V 154406584cd0SArun P. Mohanan /** @brief implements MTM BMC Feature Control IPMI command which can be 154506584cd0SArun P. Mohanan * used to enable or disable the supported BMC features. 154606584cd0SArun P. Mohanan * @param yield - context object that represents the currently executing 154706584cd0SArun P. Mohanan * coroutine 154806584cd0SArun P. Mohanan * @param feature - feature enum to enable or disable 154906584cd0SArun P. Mohanan * @param enable - enable or disable the feature 155006584cd0SArun P. Mohanan * @param featureArg - custom arguments for that feature 155106584cd0SArun P. Mohanan * @param reserved - reserved for future use 155206584cd0SArun P. Mohanan * 155306584cd0SArun P. Mohanan * @returns IPMI completion code 155406584cd0SArun P. Mohanan */ 155506584cd0SArun P. Mohanan ipmi::RspType<> mtmBMCFeatureControl(ipmi::Context::ptr ctx, 155606584cd0SArun P. Mohanan const uint8_t feature, 155706584cd0SArun P. Mohanan const uint8_t enable, 155806584cd0SArun P. Mohanan const uint8_t featureArg, 155906584cd0SArun P. Mohanan const uint16_t reserved) 156006584cd0SArun P. Mohanan { 156106584cd0SArun P. Mohanan if (reserved != 0) 156206584cd0SArun P. Mohanan { 156306584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 156406584cd0SArun P. Mohanan } 156506584cd0SArun P. Mohanan 156606584cd0SArun P. Mohanan switch (feature) 156706584cd0SArun P. Mohanan { 156806584cd0SArun P. Mohanan case ipmi::SupportedFeatureControls::mctp: 156906584cd0SArun P. Mohanan switch (featureArg) 157006584cd0SArun P. Mohanan { 157106584cd0SArun P. Mohanan case ipmi::SupportedMCTPBindings::mctpPCIe: 157206584cd0SArun P. Mohanan return handleMCTPFeature(ctx, enable, "MCTP_PCIe"); 157306584cd0SArun P. Mohanan case ipmi::SupportedMCTPBindings::mctpSMBusHSBP: 157406584cd0SArun P. Mohanan return handleMCTPFeature(ctx, enable, "MCTP_SMBus_HSBP"); 157506584cd0SArun P. Mohanan case ipmi::SupportedMCTPBindings::mctpSMBusPCIeSlot: 157606584cd0SArun P. Mohanan return handleMCTPFeature(ctx, enable, 157706584cd0SArun P. Mohanan "MCTP_SMBus_PCIe_slot"); 157806584cd0SArun P. Mohanan default: 157906584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 158006584cd0SArun P. Mohanan } 158106584cd0SArun P. Mohanan break; 15825cb2c045SJason M. Bills case ipmi::SupportedFeatureControls::pcieScan: 15835cb2c045SJason M. Bills if (featureArg != 0) 15845cb2c045SJason M. Bills { 15855cb2c045SJason M. Bills return ipmi::responseInvalidFieldRequest(); 15865cb2c045SJason M. Bills } 15875cb2c045SJason M. Bills startOrStopService(ctx, enable, "xyz.openbmc_project.PCIe.service"); 15885cb2c045SJason M. Bills break; 1589*97c30909SVasu V case ipmi::SupportedFeatureControls::mctpSlotSupport: 1590*97c30909SVasu V return handleMCTPSlotFeature(ctx, enable, featureArg); 1591*97c30909SVasu V break; 159206584cd0SArun P. Mohanan default: 159306584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 159406584cd0SArun P. Mohanan } 159506584cd0SArun P. Mohanan return ipmi::responseSuccess(); 159606584cd0SArun P. Mohanan } 1597a3702c1fSVernon Mauery } // namespace ipmi 1598a3702c1fSVernon Mauery 1599a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor)); 1600a3702c1fSVernon Mauery void register_mtm_commands() 1601a3702c1fSVernon Mauery { 160238d2b5a6SJason M. Bills // <Get SM Signal> 160398bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 160498bbf69aSVernon Mauery ipmi::intel::general::cmdGetSmSignal, 16055e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMGetSignal); 1606a3702c1fSVernon Mauery 160798bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 160898bbf69aSVernon Mauery ipmi::intel::general::cmdSetSmSignal, 16095e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMSetSignal); 1610a3702c1fSVernon Mauery 161198bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 161298bbf69aSVernon Mauery ipmi::intel::general::cmdMtmKeepAlive, 1613666dd01cSRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::mtmKeepAlive); 1614666dd01cSRichard Marian Thomaiyar 161598bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 161698bbf69aSVernon Mauery ipmi::intel::general::cmdSetManufacturingData, 16171f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::setManufacturingData); 16181f0839c2SRichard Marian Thomaiyar 161998bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 162098bbf69aSVernon Mauery ipmi::intel::general::cmdGetManufacturingData, 16211f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::getManufacturingData); 16221f0839c2SRichard Marian Thomaiyar 162327d2356eSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 162427d2356eSVernon Mauery ipmi::intel::general::cmdSetFITcLayout, 162527d2356eSVernon Mauery ipmi::Privilege::Admin, ipmi::setFITcLayout); 162627d2356eSVernon Mauery 162706584cd0SArun P. Mohanan ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 162806584cd0SArun P. Mohanan ipmi::intel::general::cmdMTMBMCFeatureControl, 162906584cd0SArun P. Mohanan ipmi::Privilege::Admin, ipmi::mtmBMCFeatureControl); 163006584cd0SArun P. Mohanan 163198bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 163280d4d5f9SMatt Simmering ipmi::intel::general::cmdSlotI2CControllerWriteRead, 163398bbf69aSVernon Mauery ipmi::Privilege::Admin, 163480d4d5f9SMatt Simmering ipmi::appSlotI2CControllerWriteRead); 1635f267a67dSYong Li 1636068b4f2cSYong Li ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform, 1637068b4f2cSYong Li ipmi::intel::platform::cmdClearCMOS, 1638068b4f2cSYong Li ipmi::Privilege::Admin, ipmi::clearCMOS); 1639068b4f2cSYong Li 164098bbf69aSVernon Mauery ipmi::registerFilter(ipmi::prioOemBase, 164185feb130SYong Li [](ipmi::message::Request::ptr request) { 164285feb130SYong Li return ipmi::mfgFilterMessage(request); 164385feb130SYong Li }); 1644a3702c1fSVernon Mauery } 1645