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> 240748c69dSJason M. Bills #include <types.hpp> 25a3702c1fSVernon Mauery 26fcd2d3a9SJames Feist #include <filesystem> 27fcd2d3a9SJames Feist #include <fstream> 28fcd2d3a9SJames Feist 29a3702c1fSVernon Mauery namespace ipmi 30a3702c1fSVernon Mauery { 31a3702c1fSVernon Mauery 32a3702c1fSVernon Mauery Manufacturing mtm; 33a3702c1fSVernon Mauery 34a3702c1fSVernon Mauery static auto revertTimeOut = 35a3702c1fSVernon Mauery std::chrono::duration_cast<std::chrono::microseconds>( 36a3702c1fSVernon Mauery std::chrono::seconds(60)); // 1 minute timeout 37a3702c1fSVernon Mauery 38f267a67dSYong Li static constexpr uint8_t slotAddressTypeBus = 0; 39f267a67dSYong Li static constexpr uint8_t slotAddressTypeUniqueid = 1; 40f267a67dSYong Li static constexpr uint8_t slotI2CMaxReadSize = 35; 41f267a67dSYong Li 42a3702c1fSVernon Mauery static constexpr const char* callbackMgrService = 43a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 44a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf = 45a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 46a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath = 47a3702c1fSVernon Mauery "/xyz/openbmc_project/CallbackManager"; 48a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; 49a3702c1fSVernon Mauery 50a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1"; 51a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; 52a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf = 53a3702c1fSVernon Mauery "org.freedesktop.systemd1.Manager"; 54a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service"; 55a3702c1fSVernon Mauery 56357ddc74SRichard Marian Thomaiyar static inline Cc resetMtmTimer(ipmi::Context::ptr ctx) 57666dd01cSRichard Marian Thomaiyar { 58666dd01cSRichard Marian Thomaiyar boost::system::error_code ec; 59357ddc74SRichard Marian Thomaiyar ctx->bus->yield_method_call<>(ctx->yield, ec, specialModeService, 60666dd01cSRichard Marian Thomaiyar specialModeObjPath, specialModeIntf, 61666dd01cSRichard Marian Thomaiyar "ResetTimer"); 62666dd01cSRichard Marian Thomaiyar if (ec) 63666dd01cSRichard Marian Thomaiyar { 64666dd01cSRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 65666dd01cSRichard Marian Thomaiyar "Failed to reset the manufacturing mode timer"); 66666dd01cSRichard Marian Thomaiyar return ccUnspecifiedError; 67666dd01cSRichard Marian Thomaiyar } 68666dd01cSRichard Marian Thomaiyar return ccSuccess; 69666dd01cSRichard Marian Thomaiyar } 70666dd01cSRichard Marian Thomaiyar 7138d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) 72a3702c1fSVernon Mauery { 7338d2b5a6SJason M. Bills switch (signal) 7438d2b5a6SJason M. Bills { 7538d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 7638d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/power"; 7738d2b5a6SJason M. Bills break; 7838d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 7938d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/reset"; 8038d2b5a6SJason M. Bills break; 8138d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 8238d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/nmi"; 8338d2b5a6SJason M. Bills break; 848e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 858e5e2b04SRichard Marian Thomaiyar path = "/xyz/openbmc_project/chassis/buttons/id"; 868e5e2b04SRichard Marian Thomaiyar break; 8738d2b5a6SJason M. Bills default: 8838d2b5a6SJason M. Bills return -1; 8938d2b5a6SJason M. Bills break; 9038d2b5a6SJason M. Bills } 9138d2b5a6SJason M. Bills return 0; 92a3702c1fSVernon Mauery } 93a3702c1fSVernon Mauery 9437890392SPatrick Venture ipmi_ret_t ledStoreAndSet(SmSignalSet signal, const std::string& setState) 95a3702c1fSVernon Mauery { 96a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 97a3702c1fSVernon Mauery if (ledProp == nullptr) 98a3702c1fSVernon Mauery { 99a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 100a3702c1fSVernon Mauery } 101a3702c1fSVernon Mauery 102a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 103a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 104a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 105a3702c1fSVernon Mauery ipmi::Value presentState; 106a3702c1fSVernon Mauery 107a3702c1fSVernon Mauery if (false == ledProp->getLock()) 108a3702c1fSVernon Mauery { 109a3702c1fSVernon Mauery if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, 110a3702c1fSVernon Mauery "State", &presentState) != 0) 111a3702c1fSVernon Mauery { 112a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 113a3702c1fSVernon Mauery } 114a3702c1fSVernon Mauery ledProp->setPrevState(std::get<std::string>(presentState)); 115a3702c1fSVernon Mauery ledProp->setLock(true); 116a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 117a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 118a3702c1fSVernon Mauery { 119a3702c1fSVernon Mauery mtm.revertLedCallback = true; 120a3702c1fSVernon Mauery } 121a3702c1fSVernon Mauery } 12238d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 123a3702c1fSVernon Mauery ledStateStr + setState) != 0) 124a3702c1fSVernon Mauery { 125a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 126a3702c1fSVernon Mauery } 127a3702c1fSVernon Mauery return IPMI_CC_OK; 128a3702c1fSVernon Mauery } 129a3702c1fSVernon Mauery 130a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal) 131a3702c1fSVernon Mauery { 132a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 133a3702c1fSVernon Mauery if (ledProp == nullptr) 134a3702c1fSVernon Mauery { 135a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 136a3702c1fSVernon Mauery } 137a3702c1fSVernon Mauery if (true == ledProp->getLock()) 138a3702c1fSVernon Mauery { 139a3702c1fSVernon Mauery ledProp->setLock(false); 140a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 141a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 142a3702c1fSVernon Mauery { 143a3702c1fSVernon Mauery try 144a3702c1fSVernon Mauery { 145a3702c1fSVernon Mauery ipmi::method_no_args::callDbusMethod( 146a3702c1fSVernon Mauery *getSdBus(), callbackMgrService, callbackMgrObjPath, 147a3702c1fSVernon Mauery callbackMgrIntf, retriggerLedUpdate); 148a3702c1fSVernon Mauery } 149bd51e6a9SPatrick Williams catch (const sdbusplus::exception_t& e) 150a3702c1fSVernon Mauery { 151a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 152a3702c1fSVernon Mauery } 153a3702c1fSVernon Mauery mtm.revertLedCallback = false; 154a3702c1fSVernon Mauery } 155a3702c1fSVernon Mauery else 156a3702c1fSVernon Mauery { 157a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 158a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 159a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 16038d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 16138d2b5a6SJason M. Bills ledProp->getPrevState()) != 0) 162a3702c1fSVernon Mauery { 163a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 164a3702c1fSVernon Mauery } 165a3702c1fSVernon Mauery } 166a3702c1fSVernon Mauery } 167a3702c1fSVernon Mauery return IPMI_CC_OK; 168a3702c1fSVernon Mauery } 169a3702c1fSVernon Mauery 170a3702c1fSVernon Mauery void Manufacturing::initData() 171a3702c1fSVernon Mauery { 172a3702c1fSVernon Mauery ledPropertyList.push_back( 173a3702c1fSVernon Mauery LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); 174a3702c1fSVernon Mauery ledPropertyList.push_back( 175a3702c1fSVernon Mauery LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); 176a3702c1fSVernon Mauery ledPropertyList.push_back( 177a3702c1fSVernon Mauery LedProperty(SmSignalSet::smIdentifyLed, "identify")); 178a3702c1fSVernon Mauery } 179a3702c1fSVernon Mauery 180a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler() 181a3702c1fSVernon Mauery { 182ae13ac62SRichard Marian Thomaiyar 183ae13ac62SRichard Marian Thomaiyar #ifdef BMC_VALIDATION_UNSECURE_FEATURE 184ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::valUnsecure) 185ae13ac62SRichard Marian Thomaiyar { 186ae13ac62SRichard Marian Thomaiyar // Don't revert the behaviour for validation unsecure mode. 187ae13ac62SRichard Marian Thomaiyar return; 188ae13ac62SRichard Marian Thomaiyar } 189ae13ac62SRichard Marian Thomaiyar #endif 190a3702c1fSVernon Mauery if (revertFanPWM) 191a3702c1fSVernon Mauery { 192a3702c1fSVernon Mauery revertFanPWM = false; 193a3702c1fSVernon Mauery disablePidControlService(false); 194a3702c1fSVernon Mauery } 195a3702c1fSVernon Mauery 196d872a4a4SAyushi Smriti if (mtmTestBeepFd != -1) 197d872a4a4SAyushi Smriti { 198d872a4a4SAyushi Smriti ::close(mtmTestBeepFd); 199d872a4a4SAyushi Smriti mtmTestBeepFd = -1; 200d872a4a4SAyushi Smriti } 201d872a4a4SAyushi Smriti 202a3702c1fSVernon Mauery for (const auto& ledProperty : ledPropertyList) 203a3702c1fSVernon Mauery { 204a3702c1fSVernon Mauery const std::string& ledName = ledProperty.getName(); 205f365614cSJayaprakash Mutyala if (ledName == "identify" && mtm.getMfgMode() == SpecialMode::mfg) 206f365614cSJayaprakash Mutyala { 207f365614cSJayaprakash Mutyala // Don't revert the behaviour for manufacturing mode 208f365614cSJayaprakash Mutyala continue; 209f365614cSJayaprakash Mutyala } 210a3702c1fSVernon Mauery ledRevert(ledProperty.getSignal()); 211a3702c1fSVernon Mauery } 212a3702c1fSVernon Mauery } 213a3702c1fSVernon Mauery 214a3702c1fSVernon Mauery Manufacturing::Manufacturing() : 215a3702c1fSVernon Mauery revertTimer([&](void) { revertTimerHandler(); }) 216a3702c1fSVernon Mauery { 217a3702c1fSVernon Mauery initData(); 218a3702c1fSVernon Mauery } 219a3702c1fSVernon Mauery 22038d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service, 22138d2b5a6SJason M. Bills const std::string& path, 22238d2b5a6SJason M. Bills const std::string& interface, 22338d2b5a6SJason M. Bills const std::string& propertyName, 22438d2b5a6SJason M. Bills ipmi::Value* reply) 225a3702c1fSVernon Mauery { 226a3702c1fSVernon Mauery try 227a3702c1fSVernon Mauery { 22838d2b5a6SJason M. Bills *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, 22938d2b5a6SJason M. Bills propertyName); 230a3702c1fSVernon Mauery } 231f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 232a3702c1fSVernon Mauery { 233a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 234a3702c1fSVernon Mauery "ERROR: getProperty"); 235a3702c1fSVernon Mauery return -1; 236a3702c1fSVernon Mauery } 237a3702c1fSVernon Mauery 238a3702c1fSVernon Mauery return 0; 239a3702c1fSVernon Mauery } 240a3702c1fSVernon Mauery 24138d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service, 24238d2b5a6SJason M. Bills const std::string& path, 24338d2b5a6SJason M. Bills const std::string& interface, 24438d2b5a6SJason M. Bills const std::string& propertyName, 24538d2b5a6SJason M. Bills ipmi::Value value) 246a3702c1fSVernon Mauery { 247a3702c1fSVernon Mauery try 248a3702c1fSVernon Mauery { 24938d2b5a6SJason M. Bills ipmi::setDbusProperty(*getSdBus(), service, path, interface, 250a3702c1fSVernon Mauery propertyName, value); 251a3702c1fSVernon Mauery } 252f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 253a3702c1fSVernon Mauery { 254a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 255a3702c1fSVernon Mauery "ERROR: setProperty"); 256a3702c1fSVernon Mauery return -1; 257a3702c1fSVernon Mauery } 258a3702c1fSVernon Mauery 259a3702c1fSVernon Mauery return 0; 260a3702c1fSVernon Mauery } 261a3702c1fSVernon Mauery 262a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable) 263a3702c1fSVernon Mauery { 264a3702c1fSVernon Mauery try 265a3702c1fSVernon Mauery { 266a3702c1fSVernon Mauery auto dbus = getSdBus(); 267a3702c1fSVernon Mauery auto method = dbus->new_method_call(systemDService, systemDObjPath, 268a3702c1fSVernon Mauery systemDMgrIntf, 269a3702c1fSVernon Mauery disable ? "StopUnit" : "StartUnit"); 270a3702c1fSVernon Mauery method.append(pidControlService, "replace"); 271a3702c1fSVernon Mauery auto reply = dbus->call(method); 272a3702c1fSVernon Mauery } 273f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 274a3702c1fSVernon Mauery { 275a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 276a3702c1fSVernon Mauery "ERROR: phosphor-pid-control service start or stop failed"); 277a3702c1fSVernon Mauery return -1; 278a3702c1fSVernon Mauery } 279a3702c1fSVernon Mauery return 0; 280a3702c1fSVernon Mauery } 281a3702c1fSVernon Mauery 28290eb7876SAlex Schendel static bool findPwmName(ipmi::Context::ptr& ctx, uint8_t instance, 28390eb7876SAlex Schendel std::string& pwmName) 28490eb7876SAlex Schendel { 28590eb7876SAlex Schendel boost::system::error_code ec{}; 28690eb7876SAlex Schendel ObjectValueTree obj; 28790eb7876SAlex Schendel 28890eb7876SAlex Schendel // GetAll the objects under service FruDevice 28990eb7876SAlex Schendel ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager", 29090eb7876SAlex Schendel "/xyz/openbmc_project/inventory", obj); 29190eb7876SAlex Schendel if (ec) 29290eb7876SAlex Schendel { 29390eb7876SAlex Schendel phosphor::logging::log<phosphor::logging::level::ERR>( 29490eb7876SAlex Schendel "GetMangagedObjects failed", 29590eb7876SAlex Schendel phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 29690eb7876SAlex Schendel return false; 29790eb7876SAlex Schendel } 29890eb7876SAlex Schendel for (const auto& [path, objData] : obj) 29990eb7876SAlex Schendel { 30090eb7876SAlex Schendel for (const auto& [intf, propMap] : objData) 30190eb7876SAlex Schendel { 30290eb7876SAlex Schendel // Currently, these are the three different fan types supported. 30390eb7876SAlex Schendel if (intf == "xyz.openbmc_project.Configuration.AspeedFan" || 30490eb7876SAlex Schendel intf == "xyz.openbmc_project.Configuration.I2CFan" || 30590eb7876SAlex Schendel intf == "xyz.openbmc_project.Configuration.NuvotonFan") 30690eb7876SAlex Schendel { 30790eb7876SAlex Schendel auto findIndex = propMap.find("Index"); 30890eb7876SAlex Schendel if (findIndex == propMap.end()) 30990eb7876SAlex Schendel { 31090eb7876SAlex Schendel continue; 31190eb7876SAlex Schendel } 31290eb7876SAlex Schendel 31390eb7876SAlex Schendel auto fanIndex = std::get_if<uint64_t>(&findIndex->second); 31490eb7876SAlex Schendel if (!fanIndex || *fanIndex != instance) 31590eb7876SAlex Schendel { 31690eb7876SAlex Schendel continue; 31790eb7876SAlex Schendel } 31890eb7876SAlex Schendel auto connector = objData.find(intf + std::string(".Connector")); 31990eb7876SAlex Schendel if (connector == objData.end()) 32090eb7876SAlex Schendel { 32190eb7876SAlex Schendel return false; 32290eb7876SAlex Schendel } 32390eb7876SAlex Schendel auto findPwmName = connector->second.find("PwmName"); 32490eb7876SAlex Schendel if (findPwmName != connector->second.end()) 32590eb7876SAlex Schendel { 32690eb7876SAlex Schendel auto fanPwmName = 32790eb7876SAlex Schendel std::get_if<std::string>(&findPwmName->second); 32890eb7876SAlex Schendel if (!fanPwmName) 32990eb7876SAlex Schendel { 33090eb7876SAlex Schendel phosphor::logging::log<phosphor::logging::level::INFO>( 33190eb7876SAlex Schendel "PwmName parse ERROR."); 33290eb7876SAlex Schendel return false; 33390eb7876SAlex Schendel } 33490eb7876SAlex Schendel pwmName = *fanPwmName; 33590eb7876SAlex Schendel return true; 33690eb7876SAlex Schendel } 33790eb7876SAlex Schendel auto findPwm = connector->second.find("Pwm"); 33890eb7876SAlex Schendel if (findPwm == connector->second.end()) 33990eb7876SAlex Schendel { 34090eb7876SAlex Schendel return false; 34190eb7876SAlex Schendel } 34290eb7876SAlex Schendel auto fanPwm = std::get_if<uint64_t>(&findPwm->second); 34390eb7876SAlex Schendel if (!fanPwm) 34490eb7876SAlex Schendel { 34590eb7876SAlex Schendel return false; 34690eb7876SAlex Schendel } 34790eb7876SAlex Schendel pwmName = "Pwm_" + std::to_string(*fanPwm + 1); 34890eb7876SAlex Schendel return true; 34990eb7876SAlex Schendel } 35090eb7876SAlex Schendel } 35190eb7876SAlex Schendel } 35290eb7876SAlex Schendel return false; 35390eb7876SAlex Schendel } 35438d2b5a6SJason M. Bills ipmi::RspType<uint8_t, // Signal value 35538d2b5a6SJason M. Bills std::optional<uint16_t> // Fan tach value 35638d2b5a6SJason M. Bills > 357357ddc74SRichard Marian Thomaiyar appMTMGetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 358147daec5SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte) 359a3702c1fSVernon Mauery { 360e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM get signal command only in 361e0511e5fSAyushi Smriti // manfacturing mode. 36238d2b5a6SJason M. Bills 36338d2b5a6SJason M. Bills SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); 36438d2b5a6SJason M. Bills SmActionGet action = static_cast<SmActionGet>(actionByte); 36538d2b5a6SJason M. Bills 36638d2b5a6SJason M. Bills switch (signalType) 36738d2b5a6SJason M. Bills { 36898705b39Sanil kumar appana case SmSignalGet::smChassisIntrusion: 36998705b39Sanil kumar appana { 37098705b39Sanil kumar appana ipmi::Value reply; 37198705b39Sanil kumar appana if (mtm.getProperty(intrusionService, intrusionPath, intrusionIntf, 37298705b39Sanil kumar appana "Status", &reply) < 0) 37398705b39Sanil kumar appana { 37498705b39Sanil kumar appana return ipmi::responseInvalidFieldRequest(); 37598705b39Sanil kumar appana } 37698705b39Sanil kumar appana std::string* intrusionStatus = std::get_if<std::string>(&reply); 37798705b39Sanil kumar appana if (!intrusionStatus) 37898705b39Sanil kumar appana { 37998705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 38098705b39Sanil kumar appana } 38198705b39Sanil kumar appana 38298705b39Sanil kumar appana uint8_t status = 0; 38398705b39Sanil kumar appana if (!intrusionStatus->compare("Normal")) 38498705b39Sanil kumar appana { 38598705b39Sanil kumar appana status = static_cast<uint8_t>(IntrusionStatus::normal); 38698705b39Sanil kumar appana } 38798705b39Sanil kumar appana else if (!intrusionStatus->compare("HardwareIntrusion")) 38898705b39Sanil kumar appana { 38998705b39Sanil kumar appana status = 39098705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::hardwareIntrusion); 39198705b39Sanil kumar appana } 39298705b39Sanil kumar appana else if (!intrusionStatus->compare("TamperingDetected")) 39398705b39Sanil kumar appana { 39498705b39Sanil kumar appana status = 39598705b39Sanil kumar appana static_cast<uint8_t>(IntrusionStatus::tamperingDetected); 39698705b39Sanil kumar appana } 39798705b39Sanil kumar appana else 39898705b39Sanil kumar appana { 39998705b39Sanil kumar appana return ipmi::responseUnspecifiedError(); 40098705b39Sanil kumar appana } 40198705b39Sanil kumar appana return ipmi::responseSuccess(status, std::nullopt); 40298705b39Sanil kumar appana } 40338d2b5a6SJason M. Bills case SmSignalGet::smFanPwmGet: 40438d2b5a6SJason M. Bills { 405a3702c1fSVernon Mauery ipmi::Value reply; 40690eb7876SAlex Schendel std::string pwmName, fullPath; 40790eb7876SAlex Schendel if (!findPwmName(ctx, instance, pwmName)) 40890eb7876SAlex Schendel { 40990eb7876SAlex Schendel // The default PWM name is Pwm_# 41090eb7876SAlex Schendel pwmName = "Pwm_" + std::to_string(instance + 1); 41190eb7876SAlex Schendel } 41290eb7876SAlex Schendel fullPath = fanPwmPath + pwmName; 41338d2b5a6SJason M. Bills if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 41438d2b5a6SJason M. Bills &reply) < 0) 41538d2b5a6SJason M. Bills { 41638d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 41738d2b5a6SJason M. Bills } 41838d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 41938d2b5a6SJason M. Bills if (doubleVal == nullptr) 42038d2b5a6SJason M. Bills { 42138d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 42238d2b5a6SJason M. Bills } 42338d2b5a6SJason M. Bills uint8_t sensorVal = std::round(*doubleVal); 424357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 42538d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 42638d2b5a6SJason M. Bills } 42738d2b5a6SJason M. Bills break; 42838d2b5a6SJason M. Bills case SmSignalGet::smFanTachometerGet: 42938d2b5a6SJason M. Bills { 430147daec5SRichard Marian Thomaiyar boost::system::error_code ec; 431147daec5SRichard Marian Thomaiyar using objFlatMap = boost::container::flat_map< 432147daec5SRichard Marian Thomaiyar std::string, boost::container::flat_map< 433147daec5SRichard Marian Thomaiyar std::string, std::vector<std::string>>>; 434147daec5SRichard Marian Thomaiyar 435357ddc74SRichard Marian Thomaiyar auto flatMap = ctx->bus->yield_method_call<objFlatMap>( 436357ddc74SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 437147daec5SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 438147daec5SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTree", 439147daec5SRichard Marian Thomaiyar fanTachBasePath, 0, std::array<const char*, 1>{fanIntf}); 440147daec5SRichard Marian Thomaiyar if (ec) 441147daec5SRichard Marian Thomaiyar { 442147daec5SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 443147daec5SRichard Marian Thomaiyar "Failed to query fan tach sub tree objects"); 444147daec5SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 445147daec5SRichard Marian Thomaiyar } 446147daec5SRichard Marian Thomaiyar if (instance >= flatMap.size()) 44738d2b5a6SJason M. Bills { 44838d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 44938d2b5a6SJason M. Bills } 450147daec5SRichard Marian Thomaiyar auto itr = flatMap.nth(instance); 45138d2b5a6SJason M. Bills ipmi::Value reply; 452147daec5SRichard Marian Thomaiyar if (mtm.getProperty(fanService, itr->first, fanIntf, "Value", 45338d2b5a6SJason M. Bills &reply) < 0) 45438d2b5a6SJason M. Bills { 45538d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 45638d2b5a6SJason M. Bills } 45738d2b5a6SJason M. Bills 45838d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 45938d2b5a6SJason M. Bills if (doubleVal == nullptr) 46038d2b5a6SJason M. Bills { 46138d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 46238d2b5a6SJason M. Bills } 46338d2b5a6SJason M. Bills uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; 46438d2b5a6SJason M. Bills std::optional<uint16_t> fanTach = std::round(*doubleVal); 46538d2b5a6SJason M. Bills 466357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 46738d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, fanTach); 46838d2b5a6SJason M. Bills } 46938d2b5a6SJason M. Bills break; 4708e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 4718e5e2b04SRichard Marian Thomaiyar { 4728e5e2b04SRichard Marian Thomaiyar if (action == SmActionGet::revert || action == SmActionGet::ignore) 4738e5e2b04SRichard Marian Thomaiyar { 4748e5e2b04SRichard Marian Thomaiyar // ButtonMasked property is not supported for ID button as it is 4758e5e2b04SRichard Marian Thomaiyar // unnecessary. Hence if requested for revert / ignore, override 4768e5e2b04SRichard Marian Thomaiyar // it to sample action to make tools happy. 4778e5e2b04SRichard Marian Thomaiyar action = SmActionGet::sample; 4788e5e2b04SRichard Marian Thomaiyar } 4798e5e2b04SRichard Marian Thomaiyar // fall-through 4808e5e2b04SRichard Marian Thomaiyar } 48138d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 48238d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 48338d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 48438d2b5a6SJason M. Bills { 48538d2b5a6SJason M. Bills std::string path; 48638d2b5a6SJason M. Bills if (getGpioPathForSmSignal(signalType, path) < 0) 48738d2b5a6SJason M. Bills { 48838d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 48938d2b5a6SJason M. Bills } 490a3702c1fSVernon Mauery 491a3702c1fSVernon Mauery switch (action) 492a3702c1fSVernon Mauery { 493a3702c1fSVernon Mauery case SmActionGet::sample: 494a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 495a3702c1fSVernon Mauery "case SmActionGet::sample"); 496a3702c1fSVernon Mauery break; 497a3702c1fSVernon Mauery case SmActionGet::ignore: 498a3702c1fSVernon Mauery { 499a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 500a3702c1fSVernon Mauery "case SmActionGet::ignore"); 50138d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 50238d2b5a6SJason M. Bills "ButtonMasked", true) < 0) 503a3702c1fSVernon Mauery { 50438d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 505a3702c1fSVernon Mauery } 506a3702c1fSVernon Mauery } 507a3702c1fSVernon Mauery break; 508a3702c1fSVernon Mauery case SmActionGet::revert: 509a3702c1fSVernon Mauery { 510a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 511a3702c1fSVernon Mauery "case SmActionGet::revert"); 51238d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 51338d2b5a6SJason M. Bills "ButtonMasked", false) < 0) 514a3702c1fSVernon Mauery { 51538d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 516a3702c1fSVernon Mauery } 517a3702c1fSVernon Mauery } 518a3702c1fSVernon Mauery break; 519a3702c1fSVernon Mauery 520a3702c1fSVernon Mauery default: 52138d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 522a3702c1fSVernon Mauery break; 523a3702c1fSVernon Mauery } 524a3702c1fSVernon Mauery 525a3702c1fSVernon Mauery ipmi::Value reply; 52638d2b5a6SJason M. Bills if (mtm.getProperty(buttonService, path, buttonIntf, 52738d2b5a6SJason M. Bills "ButtonPressed", &reply) < 0) 528a3702c1fSVernon Mauery { 52938d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 530a3702c1fSVernon Mauery } 53138d2b5a6SJason M. Bills bool* valPtr = std::get_if<bool>(&reply); 53238d2b5a6SJason M. Bills if (valPtr == nullptr) 533a3702c1fSVernon Mauery { 53438d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 535a3702c1fSVernon Mauery } 536357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 53738d2b5a6SJason M. Bills uint8_t sensorVal = *valPtr; 53838d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 539a3702c1fSVernon Mauery } 540a3702c1fSVernon Mauery break; 5411b74a210SRichard Marian Thomaiyar case SmSignalGet::smNcsiDiag: 5421b74a210SRichard Marian Thomaiyar { 5431b74a210SRichard Marian Thomaiyar constexpr const char* netBasePath = "/sys/class/net/eth"; 5441b74a210SRichard Marian Thomaiyar constexpr const char* carrierSuffix = "/carrier"; 5451b74a210SRichard Marian Thomaiyar std::ifstream netIfs(netBasePath + std::to_string(instance) + 5461b74a210SRichard Marian Thomaiyar carrierSuffix); 5471b74a210SRichard Marian Thomaiyar if (!netIfs.good()) 5481b74a210SRichard Marian Thomaiyar { 5491b74a210SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 5501b74a210SRichard Marian Thomaiyar } 5511b74a210SRichard Marian Thomaiyar std::string carrier; 5521b74a210SRichard Marian Thomaiyar netIfs >> carrier; 553357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 5541b74a210SRichard Marian Thomaiyar return ipmi::responseSuccess( 5551b74a210SRichard Marian Thomaiyar static_cast<uint8_t>(std::stoi(carrier)), std::nullopt); 5561b74a210SRichard Marian Thomaiyar } 5571b74a210SRichard Marian Thomaiyar break; 558a3702c1fSVernon Mauery default: 55938d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 560a3702c1fSVernon Mauery break; 561a3702c1fSVernon Mauery } 562a3702c1fSVernon Mauery } 563a3702c1fSVernon Mauery 564357ddc74SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(ipmi::Context::ptr ctx, uint8_t signalTypeByte, 565357ddc74SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte, 5665e3bf557SAyushi Smriti std::optional<uint8_t> pwmSpeed) 567a3702c1fSVernon Mauery { 568e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM set signal command only in 569e0511e5fSAyushi Smriti // manfacturing mode. 5705e3bf557SAyushi Smriti 5715e3bf557SAyushi Smriti SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte); 5725e3bf557SAyushi Smriti SmActionSet action = static_cast<SmActionSet>(actionByte); 5735e3bf557SAyushi Smriti Cc retCode = ccSuccess; 57413b0039dSJames Feist int8_t ret = 0; 5755e3bf557SAyushi Smriti 5765e3bf557SAyushi Smriti switch (signalType) 577a3702c1fSVernon Mauery { 578a3702c1fSVernon Mauery case SmSignalSet::smPowerFaultLed: 579a3702c1fSVernon Mauery case SmSignalSet::smSystemReadyLed: 580a3702c1fSVernon Mauery case SmSignalSet::smIdentifyLed: 5815e3bf557SAyushi Smriti switch (action) 582a3702c1fSVernon Mauery { 583a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 584a3702c1fSVernon Mauery { 585a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 586a3702c1fSVernon Mauery "case SmActionSet::forceDeasserted"); 587a3702c1fSVernon Mauery 5885e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("Off")); 5895e3bf557SAyushi Smriti if (retCode != ccSuccess) 590a3702c1fSVernon Mauery { 5915e3bf557SAyushi Smriti return ipmi::response(retCode); 592a3702c1fSVernon Mauery } 593a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 594a3702c1fSVernon Mauery } 595a3702c1fSVernon Mauery break; 596a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 597a3702c1fSVernon Mauery { 598a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 599a3702c1fSVernon Mauery "case SmActionSet::forceAsserted"); 600a3702c1fSVernon Mauery 6015e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("On")); 6025e3bf557SAyushi Smriti if (retCode != ccSuccess) 603a3702c1fSVernon Mauery { 6045e3bf557SAyushi Smriti return ipmi::response(retCode); 605a3702c1fSVernon Mauery } 606a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 6075e3bf557SAyushi Smriti if (SmSignalSet::smPowerFaultLed == signalType) 608a3702c1fSVernon Mauery { 609a3702c1fSVernon Mauery // Deassert "system ready" 6105e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed, 611a3702c1fSVernon Mauery std::string("Off")); 612a3702c1fSVernon Mauery } 6135e3bf557SAyushi Smriti else if (SmSignalSet::smSystemReadyLed == signalType) 614a3702c1fSVernon Mauery { 615a3702c1fSVernon Mauery // Deassert "fault led" 6165e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed, 617a3702c1fSVernon Mauery std::string("Off")); 618a3702c1fSVernon Mauery } 619a3702c1fSVernon Mauery } 620a3702c1fSVernon Mauery break; 621a3702c1fSVernon Mauery case SmActionSet::revert: 622a3702c1fSVernon Mauery { 623a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 624a3702c1fSVernon Mauery "case SmActionSet::revert"); 6255e3bf557SAyushi Smriti retCode = ledRevert(signalType); 626a3702c1fSVernon Mauery } 627a3702c1fSVernon Mauery break; 628a3702c1fSVernon Mauery default: 629a3702c1fSVernon Mauery { 6305e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 631a3702c1fSVernon Mauery } 632a3702c1fSVernon Mauery } 633a3702c1fSVernon Mauery break; 634a3702c1fSVernon Mauery case SmSignalSet::smFanPowerSpeed: 635a3702c1fSVernon Mauery { 6365e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (!pwmSpeed)) 637a3702c1fSVernon Mauery { 6385e3bf557SAyushi Smriti return ipmi::responseReqDataLenInvalid(); 639a3702c1fSVernon Mauery } 6405e3bf557SAyushi Smriti 6415e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100)) 6425e3bf557SAyushi Smriti { 6435e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 6445e3bf557SAyushi Smriti } 6455e3bf557SAyushi Smriti 646a3702c1fSVernon Mauery uint8_t pwmValue = 0; 6475e3bf557SAyushi Smriti switch (action) 648a3702c1fSVernon Mauery { 649a3702c1fSVernon Mauery case SmActionSet::revert: 650a3702c1fSVernon Mauery { 651a3702c1fSVernon Mauery if (mtm.revertFanPWM) 652a3702c1fSVernon Mauery { 653a3702c1fSVernon Mauery ret = mtm.disablePidControlService(false); 654a3702c1fSVernon Mauery if (ret < 0) 655a3702c1fSVernon Mauery { 6565e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 657a3702c1fSVernon Mauery } 658a3702c1fSVernon Mauery mtm.revertFanPWM = false; 659a3702c1fSVernon Mauery } 660a3702c1fSVernon Mauery } 661a3702c1fSVernon Mauery break; 662a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 663a3702c1fSVernon Mauery { 6645e3bf557SAyushi Smriti pwmValue = *pwmSpeed; 665a3702c1fSVernon Mauery } // fall-through 666a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 667a3702c1fSVernon Mauery { 668a3702c1fSVernon Mauery if (!mtm.revertFanPWM) 669a3702c1fSVernon Mauery { 670a3702c1fSVernon Mauery ret = mtm.disablePidControlService(true); 671a3702c1fSVernon Mauery if (ret < 0) 672a3702c1fSVernon Mauery { 6735e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 674a3702c1fSVernon Mauery } 675a3702c1fSVernon Mauery mtm.revertFanPWM = true; 676a3702c1fSVernon Mauery } 677a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 67890eb7876SAlex Schendel std::string pwmName, fanPwmInstancePath; 67990eb7876SAlex Schendel if (!findPwmName(ctx, instance, pwmName)) 68090eb7876SAlex Schendel { 68190eb7876SAlex Schendel pwmName = "Pwm_" + std::to_string(instance + 1); 68290eb7876SAlex Schendel } 68390eb7876SAlex Schendel fanPwmInstancePath = fanPwmPath + pwmName; 6845e3bf557SAyushi Smriti ret = 6855e3bf557SAyushi Smriti mtm.setProperty(fanService, fanPwmInstancePath, fanIntf, 6865e3bf557SAyushi Smriti "Value", static_cast<double>(pwmValue)); 687a3702c1fSVernon Mauery if (ret < 0) 688a3702c1fSVernon Mauery { 6895e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 690a3702c1fSVernon Mauery } 691a3702c1fSVernon Mauery } 692a3702c1fSVernon Mauery break; 693a3702c1fSVernon Mauery default: 694a3702c1fSVernon Mauery { 6955e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 696a3702c1fSVernon Mauery } 697a3702c1fSVernon Mauery } 698a3702c1fSVernon Mauery } 699a3702c1fSVernon Mauery break; 700d872a4a4SAyushi Smriti case SmSignalSet::smSpeaker: 701d872a4a4SAyushi Smriti { 702d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::INFO>( 703d872a4a4SAyushi Smriti "Performing Speaker SmActionSet", 704d872a4a4SAyushi Smriti phosphor::logging::entry("ACTION=%d", 705d872a4a4SAyushi Smriti static_cast<uint8_t>(action))); 706d872a4a4SAyushi Smriti switch (action) 707d872a4a4SAyushi Smriti { 708d872a4a4SAyushi Smriti case SmActionSet::forceAsserted: 709d872a4a4SAyushi Smriti { 710d872a4a4SAyushi Smriti char beepDevName[] = "/dev/input/event0"; 711d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 712d872a4a4SAyushi Smriti { 713d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::INFO>( 714d872a4a4SAyushi Smriti "mtm beep device is opened already!"); 715d872a4a4SAyushi Smriti // returning success as already beep is in progress 716d872a4a4SAyushi Smriti return ipmi::response(retCode); 717d872a4a4SAyushi Smriti } 718d872a4a4SAyushi Smriti 719d872a4a4SAyushi Smriti if ((mtm.mtmTestBeepFd = 720d872a4a4SAyushi Smriti ::open(beepDevName, O_RDWR | O_CLOEXEC)) < 0) 721d872a4a4SAyushi Smriti { 722d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::ERR>( 723d872a4a4SAyushi Smriti "Failed to open input device"); 724d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 725d872a4a4SAyushi Smriti } 726d872a4a4SAyushi Smriti 727d872a4a4SAyushi Smriti struct input_event event; 728d872a4a4SAyushi Smriti event.type = EV_SND; 729d872a4a4SAyushi Smriti event.code = SND_TONE; 730d872a4a4SAyushi Smriti event.value = 2000; 731d872a4a4SAyushi Smriti 732d872a4a4SAyushi Smriti if (::write(mtm.mtmTestBeepFd, &event, 733d872a4a4SAyushi Smriti sizeof(struct input_event)) != 734d872a4a4SAyushi Smriti sizeof(struct input_event)) 735d872a4a4SAyushi Smriti { 736d872a4a4SAyushi Smriti phosphor::logging::log<phosphor::logging::level::ERR>( 737d872a4a4SAyushi Smriti "Failed to write a tone sound event"); 738d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 739d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 740d872a4a4SAyushi Smriti return ipmi::responseUnspecifiedError(); 741d872a4a4SAyushi Smriti } 742d872a4a4SAyushi Smriti mtm.revertTimer.start(revertTimeOut); 743d872a4a4SAyushi Smriti } 744d872a4a4SAyushi Smriti break; 745d872a4a4SAyushi Smriti case SmActionSet::revert: 746d872a4a4SAyushi Smriti case SmActionSet::forceDeasserted: 747d872a4a4SAyushi Smriti { 748d872a4a4SAyushi Smriti if (mtm.mtmTestBeepFd != -1) 749d872a4a4SAyushi Smriti { 750d872a4a4SAyushi Smriti ::close(mtm.mtmTestBeepFd); 751d872a4a4SAyushi Smriti mtm.mtmTestBeepFd = -1; 752d872a4a4SAyushi Smriti } 753d872a4a4SAyushi Smriti } 754d872a4a4SAyushi Smriti break; 755d872a4a4SAyushi Smriti default: 756d872a4a4SAyushi Smriti { 757d872a4a4SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 758d872a4a4SAyushi Smriti } 759d872a4a4SAyushi Smriti } 760d872a4a4SAyushi Smriti } 761d872a4a4SAyushi Smriti break; 7623594c6d6SRichard Marian Thomaiyar case SmSignalSet::smDiskFaultLed: 7633594c6d6SRichard Marian Thomaiyar { 7643594c6d6SRichard Marian Thomaiyar boost::system::error_code ec; 7653594c6d6SRichard Marian Thomaiyar using objPaths = std::vector<std::string>; 7663594c6d6SRichard Marian Thomaiyar std::string driveBasePath = 7673594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/inventory/item/drive/"; 7683594c6d6SRichard Marian Thomaiyar static constexpr const char* driveLedIntf = 7693594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.Led.Group"; 7703594c6d6SRichard Marian Thomaiyar static constexpr const char* hsbpService = 7713594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.HsbpManager"; 7723594c6d6SRichard Marian Thomaiyar 7733594c6d6SRichard Marian Thomaiyar auto driveList = ctx->bus->yield_method_call<objPaths>( 7743594c6d6SRichard Marian Thomaiyar ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 7753594c6d6SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 7763594c6d6SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 7773594c6d6SRichard Marian Thomaiyar driveBasePath, 0, std::array<const char*, 1>{driveLedIntf}); 7783594c6d6SRichard Marian Thomaiyar if (ec) 7793594c6d6SRichard Marian Thomaiyar { 7803594c6d6SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 7813594c6d6SRichard Marian Thomaiyar "Failed to query HSBP drive sub tree objects"); 7823594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 7833594c6d6SRichard Marian Thomaiyar } 7843594c6d6SRichard Marian Thomaiyar std::string driveObjPath = 7853594c6d6SRichard Marian Thomaiyar driveBasePath + "Drive_" + std::to_string(instance + 1); 7863594c6d6SRichard Marian Thomaiyar if (std::find(driveList.begin(), driveList.end(), driveObjPath) == 7873594c6d6SRichard Marian Thomaiyar driveList.end()) 7883594c6d6SRichard Marian Thomaiyar { 7893594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 7903594c6d6SRichard Marian Thomaiyar } 7913594c6d6SRichard Marian Thomaiyar bool driveLedState = false; 7923594c6d6SRichard Marian Thomaiyar switch (action) 7933594c6d6SRichard Marian Thomaiyar { 7943594c6d6SRichard Marian Thomaiyar case SmActionSet::forceAsserted: 7953594c6d6SRichard Marian Thomaiyar { 7963594c6d6SRichard Marian Thomaiyar driveLedState = true; 7973594c6d6SRichard Marian Thomaiyar } 7983594c6d6SRichard Marian Thomaiyar break; 7993594c6d6SRichard Marian Thomaiyar case SmActionSet::revert: 8003594c6d6SRichard Marian Thomaiyar { 8013594c6d6SRichard Marian Thomaiyar driveLedState = false; 8023594c6d6SRichard Marian Thomaiyar } 8033594c6d6SRichard Marian Thomaiyar break; 8043594c6d6SRichard Marian Thomaiyar case SmActionSet::forceDeasserted: 8053594c6d6SRichard Marian Thomaiyar { 8063594c6d6SRichard Marian Thomaiyar driveLedState = false; 8073594c6d6SRichard Marian Thomaiyar } 8083594c6d6SRichard Marian Thomaiyar break; 8093594c6d6SRichard Marian Thomaiyar default: 8103594c6d6SRichard Marian Thomaiyar { 8113594c6d6SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 8123594c6d6SRichard Marian Thomaiyar } 8133594c6d6SRichard Marian Thomaiyar } 8143594c6d6SRichard Marian Thomaiyar ret = mtm.setProperty(hsbpService, driveObjPath, driveLedIntf, 8153594c6d6SRichard Marian Thomaiyar "Asserted", driveLedState); 8163594c6d6SRichard Marian Thomaiyar if (ret < 0) 8173594c6d6SRichard Marian Thomaiyar { 8183594c6d6SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 8193594c6d6SRichard Marian Thomaiyar } 8203594c6d6SRichard Marian Thomaiyar } 8213594c6d6SRichard Marian Thomaiyar break; 822a3702c1fSVernon Mauery default: 823a3702c1fSVernon Mauery { 8245e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 825a3702c1fSVernon Mauery } 826a3702c1fSVernon Mauery } 8274cc10159SRichard Marian Thomaiyar if (retCode == ccSuccess) 8284cc10159SRichard Marian Thomaiyar { 829357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 8304cc10159SRichard Marian Thomaiyar } 8315e3bf557SAyushi Smriti return ipmi::response(retCode); 832a3702c1fSVernon Mauery } 833a3702c1fSVernon Mauery 834357ddc74SRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(ipmi::Context::ptr ctx, uint8_t reserved, 835666dd01cSRichard Marian Thomaiyar const std::array<char, 5>& intentionalSignature) 836666dd01cSRichard Marian Thomaiyar { 837e0511e5fSAyushi Smriti // mfg filter logic is used to allow MTM keep alive command only in 838e0511e5fSAyushi Smriti // manfacturing mode 839e0511e5fSAyushi Smriti 840666dd01cSRichard Marian Thomaiyar constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'}; 841666dd01cSRichard Marian Thomaiyar if (intentionalSignature != signatureOk || reserved != 0) 842666dd01cSRichard Marian Thomaiyar { 843666dd01cSRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 844666dd01cSRichard Marian Thomaiyar } 845357ddc74SRichard Marian Thomaiyar return ipmi::response(resetMtmTimer(ctx)); 846666dd01cSRichard Marian Thomaiyar } 847666dd01cSRichard Marian Thomaiyar 848e0511e5fSAyushi Smriti static constexpr unsigned int makeCmdKey(unsigned int netFn, unsigned int cmd) 849e0511e5fSAyushi Smriti { 850e0511e5fSAyushi Smriti return (netFn << 8) | cmd; 851e0511e5fSAyushi Smriti } 852e0511e5fSAyushi Smriti 85385feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request) 85485feb130SYong Li { 855e0511e5fSAyushi Smriti // Restricted commands, must be executed only in Manufacturing mode 856e0511e5fSAyushi Smriti switch (makeCmdKey(request->ctx->netFn, request->ctx->cmd)) 85785feb130SYong Li { 858e0511e5fSAyushi Smriti // i2c master write read command needs additional checking 859e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnApp, ipmi::app::cmdMasterWriteRead): 86085feb130SYong Li if (request->payload.size() > 4) 86185feb130SYong Li { 862ae13ac62SRichard Marian Thomaiyar // Allow write data count > 1 only in Special mode 863ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 86485feb130SYong Li { 86585feb130SYong Li return ipmi::ccInsufficientPrivilege; 86685feb130SYong Li } 86785feb130SYong Li } 8682d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 869e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 870e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetSmSignal): 871e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 872e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetSmSignal): 873e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 874e0511e5fSAyushi Smriti ipmi::intel::general::cmdMtmKeepAlive): 875e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 876e0511e5fSAyushi Smriti ipmi::intel::general::cmdSetManufacturingData): 877e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnOemOne, 878e0511e5fSAyushi Smriti ipmi::intel::general::cmdGetManufacturingData): 87927d2356eSVernon Mauery case makeCmdKey(ipmi::intel::netFnGeneral, 88027d2356eSVernon Mauery ipmi::intel::general::cmdSetFITcLayout): 88106584cd0SArun P. Mohanan case makeCmdKey(ipmi::netFnOemOne, 88206584cd0SArun P. Mohanan ipmi::intel::general::cmdMTMBMCFeatureControl): 883e0511e5fSAyushi Smriti case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdWriteFruData): 8849a13daaeSAppaRao Puli case makeCmdKey(ipmi::netFnOemTwo, ipmi::intel::platform::cmdClearCMOS): 88585feb130SYong Li 886ae13ac62SRichard Marian Thomaiyar // Check for Special mode 887ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 888e0511e5fSAyushi Smriti { 889e0511e5fSAyushi Smriti return ipmi::ccInvalidCommand; 890e0511e5fSAyushi Smriti } 8912d4a0198Sjayaprakash Mutyala return ipmi::ccSuccess; 8922d4a0198Sjayaprakash Mutyala case makeCmdKey(ipmi::netFnStorage, ipmi::storage::cmdDeleteSelEntry): 8932d4a0198Sjayaprakash Mutyala { 8942d4a0198Sjayaprakash Mutyala return ipmi::ccInvalidCommand; 8952d4a0198Sjayaprakash Mutyala } 896e0511e5fSAyushi Smriti } 89785feb130SYong Li return ipmi::ccSuccess; 89885feb130SYong Li } 89985feb130SYong Li 9001f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxEthSize = 6; 9011f0839c2SRichard Marian Thomaiyar static constexpr uint8_t maxSupportedEth = 3; 9021f0839c2SRichard Marian Thomaiyar static constexpr const char* factoryEthAddrBaseFileName = 9031f0839c2SRichard Marian Thomaiyar "/var/sofs/factory-settings/network/mac/eth"; 9041f0839c2SRichard Marian Thomaiyar 905*097497fbSAlex Schendel bool findFruDevice(ipmi::Context::ptr& ctx, uint64_t& macOffset, 906ad129c68SZhikui Ren uint64_t& busNum, uint64_t& address) 907ad129c68SZhikui Ren { 908*097497fbSAlex Schendel boost::system::error_code ec{}; 909*097497fbSAlex Schendel ObjectValueTree obj; 910ad129c68SZhikui Ren 911ad129c68SZhikui Ren // GetAll the objects under service FruDevice 912*097497fbSAlex Schendel ec = getManagedObjects(ctx, "xyz.openbmc_project.EntityManager", 913*097497fbSAlex Schendel "/xyz/openbmc_project/inventory", obj); 914ad129c68SZhikui Ren if (ec) 915ad129c68SZhikui Ren { 916ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 917ad129c68SZhikui Ren "GetMangagedObjects failed", 918ad129c68SZhikui Ren phosphor::logging::entry("ERROR=%s", ec.message().c_str())); 919ad129c68SZhikui Ren return false; 920ad129c68SZhikui Ren } 921ad129c68SZhikui Ren 922ad129c68SZhikui Ren for (const auto& [path, fru] : obj) 923ad129c68SZhikui Ren { 924ad129c68SZhikui Ren for (const auto& [intf, propMap] : fru) 925ad129c68SZhikui Ren { 926ad129c68SZhikui Ren if (intf == "xyz.openbmc_project.Inventory.Item.Board.Motherboard") 927ad129c68SZhikui Ren { 928ad129c68SZhikui Ren auto findBus = propMap.find("FruBus"); 929ad129c68SZhikui Ren auto findAddress = propMap.find("FruAddress"); 930ad129c68SZhikui Ren auto findMacOffset = propMap.find("MacOffset"); 931ad129c68SZhikui Ren if (findBus == propMap.end() || findAddress == propMap.end() || 932ad129c68SZhikui Ren findMacOffset == propMap.end()) 933ad129c68SZhikui Ren { 934ad129c68SZhikui Ren continue; 935ad129c68SZhikui Ren } 936ad129c68SZhikui Ren 937ad129c68SZhikui Ren auto fruBus = std::get_if<uint64_t>(&findBus->second); 938ad129c68SZhikui Ren auto fruAddress = std::get_if<uint64_t>(&findAddress->second); 939ad129c68SZhikui Ren auto macFruOffset = 940ad129c68SZhikui Ren std::get_if<uint64_t>(&findMacOffset->second); 941ad129c68SZhikui Ren if (!fruBus || !fruAddress || !macFruOffset) 942ad129c68SZhikui Ren { 943ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::INFO>( 944ad129c68SZhikui Ren "ERROR: MotherBoard FRU config data type invalid, not " 945ad129c68SZhikui Ren "used"); 946ad129c68SZhikui Ren return false; 947ad129c68SZhikui Ren } 948ad129c68SZhikui Ren busNum = *fruBus; 949ad129c68SZhikui Ren address = *fruAddress; 950ad129c68SZhikui Ren macOffset = *macFruOffset; 951ad129c68SZhikui Ren return true; 952ad129c68SZhikui Ren } 953ad129c68SZhikui Ren } 954ad129c68SZhikui Ren } 955ad129c68SZhikui Ren return false; 956ad129c68SZhikui Ren } 957ad129c68SZhikui Ren 95898fa87e6SZhikui Ren static constexpr uint64_t fruEnd = 0xff; 95998fa87e6SZhikui Ren // write rolls over within current page, need to keep mac within a page 96098fa87e6SZhikui Ren static constexpr uint64_t fruPageSize = 0x8; 96198fa87e6SZhikui Ren // MAC record struct: HEADER, MAC DATA, CheckSum 96298fa87e6SZhikui Ren static constexpr uint64_t macRecordSize = maxEthSize + 2; 96398fa87e6SZhikui Ren static_assert(fruPageSize >= macRecordSize, 96498fa87e6SZhikui Ren "macRecordSize greater than eeprom page size"); 96598fa87e6SZhikui Ren static constexpr uint8_t macHeader = 0x40; 96698fa87e6SZhikui Ren // Calculate new checksum for fru info area 96798fa87e6SZhikui Ren static uint8_t calculateChecksum(std::vector<uint8_t>::const_iterator iter, 96898fa87e6SZhikui Ren std::vector<uint8_t>::const_iterator end) 96998fa87e6SZhikui Ren { 97098fa87e6SZhikui Ren constexpr int checksumMod = 256; 97198fa87e6SZhikui Ren uint8_t sum = std::accumulate(iter, end, static_cast<uint8_t>(0)); 97298fa87e6SZhikui Ren return (checksumMod - sum) % checksumMod; 97398fa87e6SZhikui Ren } 97498fa87e6SZhikui Ren 975ad129c68SZhikui Ren bool readMacFromFru(ipmi::Context::ptr ctx, uint8_t macIndex, 976ad129c68SZhikui Ren std::array<uint8_t, maxEthSize>& ethData) 977ad129c68SZhikui Ren { 978ad129c68SZhikui Ren uint64_t macOffset = fruEnd; 979ad129c68SZhikui Ren uint64_t fruBus = 0; 980ad129c68SZhikui Ren uint64_t fruAddress = 0; 981ad129c68SZhikui Ren 982*097497fbSAlex Schendel if (findFruDevice(ctx, macOffset, fruBus, fruAddress)) 983ad129c68SZhikui Ren { 984ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::INFO>( 985ad129c68SZhikui Ren "Found mac fru", 986ad129c68SZhikui Ren phosphor::logging::entry("BUS=%d", static_cast<uint8_t>(fruBus)), 987ad129c68SZhikui Ren phosphor::logging::entry("ADDRESS=%d", 988ad129c68SZhikui Ren static_cast<uint8_t>(fruAddress))); 989ad129c68SZhikui Ren 99098fa87e6SZhikui Ren if (macOffset % fruPageSize) 99198fa87e6SZhikui Ren { 99298fa87e6SZhikui Ren macOffset = (macOffset / fruPageSize + 1) * fruPageSize; 99398fa87e6SZhikui Ren } 99498fa87e6SZhikui Ren macOffset += macIndex * fruPageSize; 99598fa87e6SZhikui Ren if ((macOffset + macRecordSize) > fruEnd) 996ad129c68SZhikui Ren { 997ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 998ad129c68SZhikui Ren "ERROR: read fru mac failed, offset invalid"); 999ad129c68SZhikui Ren return false; 1000ad129c68SZhikui Ren } 1001ad129c68SZhikui Ren std::vector<uint8_t> writeData; 100298fa87e6SZhikui Ren writeData.push_back(static_cast<uint8_t>(macOffset)); 100398fa87e6SZhikui Ren std::vector<uint8_t> readBuf(macRecordSize); 1004ad129c68SZhikui Ren std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus); 1005ad129c68SZhikui Ren ipmi::Cc retI2C = 1006ad129c68SZhikui Ren ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf); 1007ad129c68SZhikui Ren if (retI2C == ipmi::ccSuccess) 1008ad129c68SZhikui Ren { 100998fa87e6SZhikui Ren uint8_t cs = calculateChecksum(readBuf.cbegin(), readBuf.cend()); 101098fa87e6SZhikui Ren if (cs == 0) 101198fa87e6SZhikui Ren { 101298fa87e6SZhikui Ren std::copy(++readBuf.begin(), --readBuf.end(), ethData.data()); 1013ad129c68SZhikui Ren return true; 1014ad129c68SZhikui Ren } 1015ad129c68SZhikui Ren } 101698fa87e6SZhikui Ren } 1017ad129c68SZhikui Ren return false; 1018ad129c68SZhikui Ren } 1019ad129c68SZhikui Ren 1020ad129c68SZhikui Ren ipmi::Cc writeMacToFru(ipmi::Context::ptr ctx, uint8_t macIndex, 1021ad129c68SZhikui Ren std::array<uint8_t, maxEthSize>& ethData) 1022ad129c68SZhikui Ren { 1023ad129c68SZhikui Ren uint64_t macOffset = fruEnd; 1024ad129c68SZhikui Ren uint64_t fruBus = 0; 1025ad129c68SZhikui Ren uint64_t fruAddress = 0; 1026ad129c68SZhikui Ren 1027*097497fbSAlex Schendel if (findFruDevice(ctx, macOffset, fruBus, fruAddress)) 1028ad129c68SZhikui Ren { 1029ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::INFO>( 1030ad129c68SZhikui Ren "Found mac fru", 1031ad129c68SZhikui Ren phosphor::logging::entry("BUS=%d", static_cast<uint8_t>(fruBus)), 1032ad129c68SZhikui Ren phosphor::logging::entry("ADDRESS=%d", 1033ad129c68SZhikui Ren static_cast<uint8_t>(fruAddress))); 1034ad129c68SZhikui Ren 103598fa87e6SZhikui Ren if (macOffset % fruPageSize) 103698fa87e6SZhikui Ren { 103798fa87e6SZhikui Ren macOffset = (macOffset / fruPageSize + 1) * fruPageSize; 103898fa87e6SZhikui Ren } 103998fa87e6SZhikui Ren macOffset += macIndex * fruPageSize; 104098fa87e6SZhikui Ren if ((macOffset + macRecordSize) > fruEnd) 1041ad129c68SZhikui Ren { 1042ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 1043ad129c68SZhikui Ren "ERROR: write mac fru failed, offset invalid."); 1044ad129c68SZhikui Ren return ipmi::ccParmOutOfRange; 1045ad129c68SZhikui Ren } 1046ad129c68SZhikui Ren std::vector<uint8_t> writeData; 104798fa87e6SZhikui Ren writeData.reserve(macRecordSize + 1); // include start location 104898fa87e6SZhikui Ren writeData.push_back(static_cast<uint8_t>(macOffset)); 104998fa87e6SZhikui Ren writeData.push_back(macHeader); 1050ad129c68SZhikui Ren std::for_each(ethData.cbegin(), ethData.cend(), 1051ad129c68SZhikui Ren [&](uint8_t i) { writeData.push_back(i); }); 105298fa87e6SZhikui Ren uint8_t macCheckSum = 105398fa87e6SZhikui Ren calculateChecksum(++writeData.cbegin(), writeData.cend()); 105498fa87e6SZhikui Ren writeData.push_back(macCheckSum); 1055ad129c68SZhikui Ren 1056ad129c68SZhikui Ren std::string i2cBus = "/dev/i2c-" + std::to_string(fruBus); 1057ad129c68SZhikui Ren std::vector<uint8_t> readBuf; 1058ad129c68SZhikui Ren ipmi::Cc ret = 1059ad129c68SZhikui Ren ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, readBuf); 106098fa87e6SZhikui Ren 10610408e79eSZhikui Ren // prepare for read to detect chip is write protected 10620408e79eSZhikui Ren writeData.resize(1); 10630408e79eSZhikui Ren readBuf.resize(maxEthSize + 1); // include macHeader 10640408e79eSZhikui Ren 1065ad129c68SZhikui Ren switch (ret) 1066ad129c68SZhikui Ren { 1067ad129c68SZhikui Ren case ipmi::ccSuccess: 106898fa87e6SZhikui Ren // Wait for internal write cycle to complete 106998fa87e6SZhikui Ren // example: ATMEL 24c0x chip has Twr spec as 5ms 107098fa87e6SZhikui Ren 107198fa87e6SZhikui Ren // Ideally we want yield wait, but currently following code 107298fa87e6SZhikui Ren // crash with "thread not supported" 107398fa87e6SZhikui Ren // boost::asio::deadline_timer timer( 107498fa87e6SZhikui Ren // boost::asio::get_associated_executor(ctx->yield), 107598fa87e6SZhikui Ren // boost::posix_time::seconds(1)); 107698fa87e6SZhikui Ren // timer.async_wait(ctx->yield); 107798fa87e6SZhikui Ren // use usleep as temp WA 107898fa87e6SZhikui Ren usleep(5000); 107998fa87e6SZhikui Ren if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, 108098fa87e6SZhikui Ren readBuf) == ipmi::ccSuccess) 1081ad129c68SZhikui Ren { 1082ad129c68SZhikui Ren if (std::equal(ethData.begin(), ethData.end(), 108398fa87e6SZhikui Ren ++readBuf.begin())) // skip macHeader 1084ad129c68SZhikui Ren { 1085ad129c68SZhikui Ren return ipmi::ccSuccess; 1086ad129c68SZhikui Ren } 1087ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::INFO>( 1088ad129c68SZhikui Ren "INFO: write mac fru verify failed, fru may be write " 1089ad129c68SZhikui Ren "protected."); 1090ad129c68SZhikui Ren } 1091ad129c68SZhikui Ren return ipmi::ccCommandNotAvailable; 10920408e79eSZhikui Ren default: 10930408e79eSZhikui Ren if (ipmi::i2cWriteRead(i2cBus, fruAddress, writeData, 10940408e79eSZhikui Ren readBuf) == ipmi::ccSuccess) 10950408e79eSZhikui Ren { 10960408e79eSZhikui Ren phosphor::logging::log<phosphor::logging::level::INFO>( 10970408e79eSZhikui Ren "INFO: write mac fru failed, but successfully read " 10980408e79eSZhikui Ren "from fru, fru may be write protected."); 10990408e79eSZhikui Ren return ipmi::ccCommandNotAvailable; 11000408e79eSZhikui Ren } 11010408e79eSZhikui Ren else // assume failure is due to no eeprom on board 11020408e79eSZhikui Ren { 1103ad129c68SZhikui Ren phosphor::logging::log<phosphor::logging::level::ERR>( 1104ad129c68SZhikui Ren "ERROR: write mac fru failed, assume no eeprom is " 1105ad129c68SZhikui Ren "available."); 11060408e79eSZhikui Ren } 1107ad129c68SZhikui Ren break; 1108ad129c68SZhikui Ren } 1109ad129c68SZhikui Ren } 1110ad129c68SZhikui Ren // no FRU eeprom found 1111ad129c68SZhikui Ren return ipmi::ccDestinationUnavailable; 1112ad129c68SZhikui Ren } 1113ad129c68SZhikui Ren 1114357ddc74SRichard Marian Thomaiyar ipmi::RspType<> setManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType, 11151f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData) 11161f0839c2SRichard Marian Thomaiyar { 1117ad129c68SZhikui Ren // mfg filter logic will restrict this command executing only in mfg 1118ad129c68SZhikui Ren // mode. 11191f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 11201f0839c2SRichard Marian Thomaiyar { 11211f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 11221f0839c2SRichard Marian Thomaiyar } 11231f0839c2SRichard Marian Thomaiyar 11241f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 11251f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 1126ad129c68SZhikui Ren 1127ad129c68SZhikui Ren ipmi::Cc ret = writeMacToFru(ctx, dataType, ethData); 1128ad129c68SZhikui Ren if (ret != ipmi::ccDestinationUnavailable) 1129ad129c68SZhikui Ren { 1130ad129c68SZhikui Ren resetMtmTimer(ctx); 1131ad129c68SZhikui Ren return response(ret); 1132ad129c68SZhikui Ren } 1133ad129c68SZhikui Ren 11341f0839c2SRichard Marian Thomaiyar constexpr uint8_t ethAddrStrSize = 11351f0839c2SRichard Marian Thomaiyar 19; // XX:XX:XX:XX:XX:XX + \n + null termination; 11361f0839c2SRichard Marian Thomaiyar std::vector<uint8_t> buff(ethAddrStrSize); 11371f0839c2SRichard Marian Thomaiyar std::snprintf(reinterpret_cast<char*>(buff.data()), ethAddrStrSize, 11381f0839c2SRichard Marian Thomaiyar "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx\n", ethData.at(0), 11391f0839c2SRichard Marian Thomaiyar ethData.at(1), ethData.at(2), ethData.at(3), ethData.at(4), 11401f0839c2SRichard Marian Thomaiyar ethData.at(5)); 11411f0839c2SRichard Marian Thomaiyar std::ofstream oEthFile(factoryEthAddrBaseFileName + 11421f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 11431f0839c2SRichard Marian Thomaiyar std::ofstream::out); 11441f0839c2SRichard Marian Thomaiyar if (!oEthFile.good()) 11451f0839c2SRichard Marian Thomaiyar { 11461f0839c2SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 11471f0839c2SRichard Marian Thomaiyar } 11481f0839c2SRichard Marian Thomaiyar 11491f0839c2SRichard Marian Thomaiyar oEthFile << reinterpret_cast<char*>(buff.data()); 11506d83e4eeSJohnathan Mantey oEthFile.flush(); 11511f0839c2SRichard Marian Thomaiyar oEthFile.close(); 11521f0839c2SRichard Marian Thomaiyar 1153357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 11541f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(); 11551f0839c2SRichard Marian Thomaiyar } 11561f0839c2SRichard Marian Thomaiyar 11571f0839c2SRichard Marian Thomaiyar ipmi::RspType<uint8_t, std::array<uint8_t, maxEthSize>> 1158357ddc74SRichard Marian Thomaiyar getManufacturingData(ipmi::Context::ptr ctx, uint8_t dataType) 11591f0839c2SRichard Marian Thomaiyar { 1160ad129c68SZhikui Ren // mfg filter logic will restrict this command executing only in mfg 1161ad129c68SZhikui Ren // mode. 11621f0839c2SRichard Marian Thomaiyar if (dataType >= maxSupportedEth) 11631f0839c2SRichard Marian Thomaiyar { 11641f0839c2SRichard Marian Thomaiyar return ipmi::responseParmOutOfRange(); 11651f0839c2SRichard Marian Thomaiyar } 11661f0839c2SRichard Marian Thomaiyar std::array<uint8_t, maxEthSize> ethData{0}; 11671f0839c2SRichard Marian Thomaiyar constexpr uint8_t invalidData = 0; 11681f0839c2SRichard Marian Thomaiyar constexpr uint8_t validData = 1; 11691f0839c2SRichard Marian Thomaiyar 11701f0839c2SRichard Marian Thomaiyar std::ifstream iEthFile(factoryEthAddrBaseFileName + 11711f0839c2SRichard Marian Thomaiyar std::to_string(dataType), 11721f0839c2SRichard Marian Thomaiyar std::ifstream::in); 11731f0839c2SRichard Marian Thomaiyar if (!iEthFile.good()) 11741f0839c2SRichard Marian Thomaiyar { 1175ad129c68SZhikui Ren if (readMacFromFru(ctx, dataType, ethData)) 1176ad129c68SZhikui Ren { 1177ad129c68SZhikui Ren resetMtmTimer(ctx); 1178ad129c68SZhikui Ren return ipmi::responseSuccess(validData, ethData); 1179ad129c68SZhikui Ren } 11801f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(invalidData, ethData); 11811f0839c2SRichard Marian Thomaiyar } 11821f0839c2SRichard Marian Thomaiyar std::string ethStr; 11831f0839c2SRichard Marian Thomaiyar iEthFile >> ethStr; 11841f0839c2SRichard Marian Thomaiyar uint8_t* data = ethData.data(); 11851f0839c2SRichard Marian Thomaiyar std::sscanf(ethStr.c_str(), "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx", 11861f0839c2SRichard Marian Thomaiyar data, (data + 1), (data + 2), (data + 3), (data + 4), 11871f0839c2SRichard Marian Thomaiyar (data + 5)); 11881f0839c2SRichard Marian Thomaiyar 1189357ddc74SRichard Marian Thomaiyar resetMtmTimer(ctx); 11901f0839c2SRichard Marian Thomaiyar return ipmi::responseSuccess(validData, ethData); 11911f0839c2SRichard Marian Thomaiyar } 11921f0839c2SRichard Marian Thomaiyar 1193ad129c68SZhikui Ren /** @brief implements slot master write read IPMI command which can be used 1194ad129c68SZhikui Ren * for low-level I2C/SMBus write, read or write-read access for PCIE slots 1195f267a67dSYong Li * @param reserved - skip 6 bit 1196f267a67dSYong Li * @param addressType - address type 1197f267a67dSYong Li * @param bbSlotNum - baseboard slot number 1198f267a67dSYong Li * @param riserSlotNum - riser slot number 1199f267a67dSYong Li * @param reserved2 - skip 2 bit 1200f267a67dSYong Li * @param slaveAddr - slave address 1201f267a67dSYong Li * @param readCount - number of bytes to be read 1202f267a67dSYong Li * @param writeData - data to be written 1203f267a67dSYong Li * 1204f267a67dSYong Li * @returns IPMI completion code plus response data 1205f267a67dSYong Li */ 1206f267a67dSYong Li ipmi::RspType<std::vector<uint8_t>> 1207f267a67dSYong Li appSlotI2CMasterWriteRead(uint6_t reserved, uint2_t addressType, 1208f267a67dSYong Li uint3_t bbSlotNum, uint3_t riserSlotNum, 1209fc3bc381SVernon Mauery uint2_t reserved2, uint8_t slaveAddr, 1210f267a67dSYong Li uint8_t readCount, std::vector<uint8_t> writeData) 1211f267a67dSYong Li { 1212fc3bc381SVernon Mauery if (reserved || reserved2) 1213fc3bc381SVernon Mauery { 1214fc3bc381SVernon Mauery return ipmi::responseInvalidFieldRequest(); 1215fc3bc381SVernon Mauery } 1216f267a67dSYong Li const size_t writeCount = writeData.size(); 1217f267a67dSYong Li std::string i2cBus; 1218f267a67dSYong Li if (addressType == slotAddressTypeBus) 1219f267a67dSYong Li { 1220f267a67dSYong Li std::string path = "/dev/i2c-mux/Riser_" + 1221f267a67dSYong Li std::to_string(static_cast<uint8_t>(bbSlotNum)) + 1222f267a67dSYong Li "_Mux/Pcie_Slot_" + 1223f267a67dSYong Li std::to_string(static_cast<uint8_t>(riserSlotNum)); 1224f267a67dSYong Li 1225f267a67dSYong Li if (std::filesystem::exists(path) && std::filesystem::is_symlink(path)) 1226f267a67dSYong Li { 1227f267a67dSYong Li i2cBus = std::filesystem::read_symlink(path); 1228f267a67dSYong Li } 1229f267a67dSYong Li else 1230f267a67dSYong Li { 1231f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 1232f267a67dSYong Li "Master write read command: Cannot get BusID"); 1233f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 1234f267a67dSYong Li } 1235f267a67dSYong Li } 1236f267a67dSYong Li else if (addressType == slotAddressTypeUniqueid) 1237f267a67dSYong Li { 1238f267a67dSYong Li i2cBus = "/dev/i2c-" + 1239f267a67dSYong Li std::to_string(static_cast<uint8_t>(bbSlotNum) | 1240f267a67dSYong Li (static_cast<uint8_t>(riserSlotNum) << 3)); 1241f267a67dSYong Li } 1242f267a67dSYong Li else 1243f267a67dSYong Li { 1244f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 1245f267a67dSYong Li "Master write read command: invalid request"); 1246f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 1247f267a67dSYong Li } 1248f267a67dSYong Li 1249ad129c68SZhikui Ren // Allow single byte write as it is offset byte to read the data, rest 1250ad129c68SZhikui Ren // allow only in Special mode. 1251f267a67dSYong Li if (writeCount > 1) 1252f267a67dSYong Li { 1253ae13ac62SRichard Marian Thomaiyar if (mtm.getMfgMode() == SpecialMode::none) 1254f267a67dSYong Li { 1255f267a67dSYong Li return ipmi::responseInsufficientPrivilege(); 1256f267a67dSYong Li } 1257f267a67dSYong Li } 1258f267a67dSYong Li 1259f267a67dSYong Li if (readCount > slotI2CMaxReadSize) 1260f267a67dSYong Li { 1261f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 1262f267a67dSYong Li "Master write read command: Read count exceeds limit"); 1263f267a67dSYong Li return ipmi::responseParmOutOfRange(); 1264f267a67dSYong Li } 1265f267a67dSYong Li 1266f267a67dSYong Li if (!readCount && !writeCount) 1267f267a67dSYong Li { 1268f267a67dSYong Li phosphor::logging::log<phosphor::logging::level::ERR>( 1269f267a67dSYong Li "Master write read command: Read & write count are 0"); 1270f267a67dSYong Li return ipmi::responseInvalidFieldRequest(); 1271f267a67dSYong Li } 1272f267a67dSYong Li 1273f267a67dSYong Li std::vector<uint8_t> readBuf(readCount); 1274f267a67dSYong Li 1275f267a67dSYong Li ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf); 1276f267a67dSYong Li if (retI2C != ipmi::ccSuccess) 1277f267a67dSYong Li { 1278f267a67dSYong Li return ipmi::response(retI2C); 1279f267a67dSYong Li } 1280f267a67dSYong Li 1281f267a67dSYong Li return ipmi::responseSuccess(readBuf); 1282f267a67dSYong Li } 1283068b4f2cSYong Li 1284068b4f2cSYong Li ipmi::RspType<> clearCMOS() 1285068b4f2cSYong Li { 1286ad129c68SZhikui Ren // There is an i2c device on bus 4, the slave address is 0x38. Based on 1287ad129c68SZhikui Ren // the spec, writing 0x1 to address 0x61 on this device, will trigger 1288ad129c68SZhikui Ren // the clear CMOS action. 1289d0d010b7SYong Li constexpr uint8_t slaveAddr = 0x38; 1290068b4f2cSYong Li std::string i2cBus = "/dev/i2c-4"; 1291eaeb6cb0SYong Li std::vector<uint8_t> writeData = {0x61, 0x1}; 1292068b4f2cSYong Li std::vector<uint8_t> readBuf(0); 1293068b4f2cSYong Li 1294068b4f2cSYong Li ipmi::Cc retI2C = ipmi::i2cWriteRead(i2cBus, slaveAddr, writeData, readBuf); 1295068b4f2cSYong Li return ipmi::response(retI2C); 1296068b4f2cSYong Li } 129727d2356eSVernon Mauery 129827d2356eSVernon Mauery ipmi::RspType<> setFITcLayout(uint32_t layout) 129927d2356eSVernon Mauery { 130027d2356eSVernon Mauery static constexpr const char* factoryFITcLayout = 130127d2356eSVernon Mauery "/var/sofs/factory-settings/layout/fitc"; 130227d2356eSVernon Mauery std::filesystem::path fitcDir = 130327d2356eSVernon Mauery std::filesystem::path(factoryFITcLayout).parent_path(); 130427d2356eSVernon Mauery std::error_code ec; 130527d2356eSVernon Mauery std::filesystem::create_directories(fitcDir, ec); 130627d2356eSVernon Mauery if (ec) 130727d2356eSVernon Mauery { 130827d2356eSVernon Mauery return ipmi::responseUnspecifiedError(); 130927d2356eSVernon Mauery } 131027d2356eSVernon Mauery try 131127d2356eSVernon Mauery { 131227d2356eSVernon Mauery std::ofstream file(factoryFITcLayout); 131327d2356eSVernon Mauery file << layout; 131427d2356eSVernon Mauery file.flush(); 131527d2356eSVernon Mauery file.close(); 131627d2356eSVernon Mauery } 131727d2356eSVernon Mauery catch (const std::exception& e) 131827d2356eSVernon Mauery { 131927d2356eSVernon Mauery return ipmi::responseUnspecifiedError(); 132027d2356eSVernon Mauery } 132127d2356eSVernon Mauery 132227d2356eSVernon Mauery return ipmi::responseSuccess(); 132327d2356eSVernon Mauery } 132427d2356eSVernon Mauery 132506584cd0SArun P. Mohanan static std::vector<std::string> 132606584cd0SArun P. Mohanan getMCTPServiceConfigPaths(ipmi::Context::ptr& ctx) 132706584cd0SArun P. Mohanan { 132806584cd0SArun P. Mohanan boost::system::error_code ec; 132906584cd0SArun P. Mohanan auto configPaths = ctx->bus->yield_method_call<std::vector<std::string>>( 133006584cd0SArun P. Mohanan ctx->yield, ec, "xyz.openbmc_project.ObjectMapper", 133106584cd0SArun P. Mohanan "/xyz/openbmc_project/object_mapper", 133206584cd0SArun P. Mohanan "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", 133306584cd0SArun P. Mohanan "/xyz/openbmc_project/inventory/system/board", 2, 133406584cd0SArun P. Mohanan std::array<const char*, 1>{ 133506584cd0SArun P. Mohanan "xyz.openbmc_project.Configuration.MctpConfiguration"}); 133606584cd0SArun P. Mohanan if (ec) 133706584cd0SArun P. Mohanan { 133806584cd0SArun P. Mohanan throw std::runtime_error( 133906584cd0SArun P. Mohanan "Failed to query configuration sub tree objects"); 134006584cd0SArun P. Mohanan } 134106584cd0SArun P. Mohanan return configPaths; 134206584cd0SArun P. Mohanan } 134306584cd0SArun P. Mohanan 134406584cd0SArun P. Mohanan static ipmi::RspType<> startOrStopService(ipmi::Context::ptr& ctx, 134506584cd0SArun P. Mohanan const uint8_t enable, 13461fe485cdSANJALI RAY const std::string& serviceName, 13471fe485cdSANJALI RAY bool disableOrEnableUnitFiles = true) 134806584cd0SArun P. Mohanan { 134906584cd0SArun P. Mohanan constexpr bool runtimeOnly = false; 135006584cd0SArun P. Mohanan constexpr bool force = false; 135106584cd0SArun P. Mohanan 135206584cd0SArun P. Mohanan boost::system::error_code ec; 135306584cd0SArun P. Mohanan switch (enable) 135406584cd0SArun P. Mohanan { 135506584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::stop: 135606584cd0SArun P. Mohanan ctx->bus->yield_method_call(ctx->yield, ec, systemDService, 135706584cd0SArun P. Mohanan systemDObjPath, systemDMgrIntf, 135806584cd0SArun P. Mohanan "StopUnit", serviceName, "replace"); 135906584cd0SArun P. Mohanan break; 136006584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::start: 136106584cd0SArun P. Mohanan ctx->bus->yield_method_call(ctx->yield, ec, systemDService, 136206584cd0SArun P. Mohanan systemDObjPath, systemDMgrIntf, 136306584cd0SArun P. Mohanan "StartUnit", serviceName, "replace"); 136406584cd0SArun P. Mohanan break; 136506584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::disable: 13661fe485cdSANJALI RAY if (disableOrEnableUnitFiles == true) 13671fe485cdSANJALI RAY { 13681fe485cdSANJALI RAY ctx->bus->yield_method_call( 13691fe485cdSANJALI RAY ctx->yield, ec, systemDService, systemDObjPath, 13701fe485cdSANJALI RAY systemDMgrIntf, "DisableUnitFiles", 13711fe485cdSANJALI RAY std::array<const char*, 1>{serviceName.c_str()}, 13721fe485cdSANJALI RAY runtimeOnly); 13731fe485cdSANJALI RAY } 137406584cd0SArun P. Mohanan ctx->bus->yield_method_call( 137506584cd0SArun P. Mohanan ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf, 137606584cd0SArun P. Mohanan "MaskUnitFiles", 137706584cd0SArun P. Mohanan std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly, 137806584cd0SArun P. Mohanan force); 137906584cd0SArun P. Mohanan break; 138006584cd0SArun P. Mohanan case ipmi::SupportedFeatureActions::enable: 138106584cd0SArun P. Mohanan ctx->bus->yield_method_call( 138206584cd0SArun P. Mohanan ctx->yield, ec, systemDService, systemDObjPath, systemDMgrIntf, 138306584cd0SArun P. Mohanan "UnmaskUnitFiles", 138406584cd0SArun P. Mohanan std::array<const char*, 1>{serviceName.c_str()}, runtimeOnly); 13851fe485cdSANJALI RAY if (disableOrEnableUnitFiles == true) 13861fe485cdSANJALI RAY { 138706584cd0SArun P. Mohanan ctx->bus->yield_method_call( 13881fe485cdSANJALI RAY ctx->yield, ec, systemDService, systemDObjPath, 13891fe485cdSANJALI RAY systemDMgrIntf, "EnableUnitFiles", 13901fe485cdSANJALI RAY std::array<const char*, 1>{serviceName.c_str()}, 13911fe485cdSANJALI RAY runtimeOnly, force); 13921fe485cdSANJALI RAY } 139306584cd0SArun P. Mohanan break; 139406584cd0SArun P. Mohanan default: 139506584cd0SArun P. Mohanan phosphor::logging::log<phosphor::logging::level::WARNING>( 139606584cd0SArun P. Mohanan "ERROR: Invalid feature action selected", 139706584cd0SArun P. Mohanan phosphor::logging::entry("ACTION=%d", enable)); 139806584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 139906584cd0SArun P. Mohanan } 140006584cd0SArun P. Mohanan if (ec) 140106584cd0SArun P. Mohanan { 140206584cd0SArun P. Mohanan phosphor::logging::log<phosphor::logging::level::WARNING>( 140306584cd0SArun P. Mohanan "ERROR: Service start or stop failed", 140406584cd0SArun P. Mohanan phosphor::logging::entry("SERVICE=%s", serviceName.c_str())); 140506584cd0SArun P. Mohanan return ipmi::responseUnspecifiedError(); 140606584cd0SArun P. Mohanan } 140706584cd0SArun P. Mohanan return ipmi::responseSuccess(); 140806584cd0SArun P. Mohanan } 140906584cd0SArun P. Mohanan 141006584cd0SArun P. Mohanan static std::string getMCTPServiceName(const std::string& objectPath) 141106584cd0SArun P. Mohanan { 141206584cd0SArun P. Mohanan const auto serviceArgument = boost::algorithm::replace_all_copy( 141306584cd0SArun P. Mohanan boost::algorithm::replace_first_copy( 141406584cd0SArun P. Mohanan objectPath, "/xyz/openbmc_project/inventory/system/board/", ""), 141506584cd0SArun P. Mohanan "/", "_2f"); 141606584cd0SArun P. Mohanan std::string unitName = 141706584cd0SArun P. Mohanan "xyz.openbmc_project.mctpd@" + serviceArgument + ".service"; 141806584cd0SArun P. Mohanan return unitName; 141906584cd0SArun P. Mohanan } 142006584cd0SArun P. Mohanan 142106584cd0SArun P. Mohanan static ipmi::RspType<> handleMCTPFeature(ipmi::Context::ptr& ctx, 142206584cd0SArun P. Mohanan const uint8_t enable, 142306584cd0SArun P. Mohanan const std::string& binding) 142406584cd0SArun P. Mohanan { 142506584cd0SArun P. Mohanan std::vector<std::string> configPaths; 142606584cd0SArun P. Mohanan try 142706584cd0SArun P. Mohanan { 142806584cd0SArun P. Mohanan configPaths = getMCTPServiceConfigPaths(ctx); 142906584cd0SArun P. Mohanan } 143006584cd0SArun P. Mohanan catch (const std::exception& e) 143106584cd0SArun P. Mohanan { 143206584cd0SArun P. Mohanan phosphor::logging::log<phosphor::logging::level::ERR>(e.what()); 143306584cd0SArun P. Mohanan return ipmi::responseUnspecifiedError(); 143406584cd0SArun P. Mohanan } 143506584cd0SArun P. Mohanan 143606584cd0SArun P. Mohanan for (const auto& objectPath : configPaths) 143706584cd0SArun P. Mohanan { 143806584cd0SArun P. Mohanan auto const pos = objectPath.find_last_of('/'); 143906584cd0SArun P. Mohanan if (binding == objectPath.substr(pos + 1)) 144006584cd0SArun P. Mohanan { 144106584cd0SArun P. Mohanan return startOrStopService(ctx, enable, 14421fe485cdSANJALI RAY getMCTPServiceName(objectPath), false); 144306584cd0SArun P. Mohanan } 144406584cd0SArun P. Mohanan } 144506584cd0SArun P. Mohanan return ipmi::responseSuccess(); 144606584cd0SArun P. Mohanan } 144706584cd0SArun P. Mohanan 144806584cd0SArun P. Mohanan /** @brief implements MTM BMC Feature Control IPMI command which can be 144906584cd0SArun P. Mohanan * used to enable or disable the supported BMC features. 145006584cd0SArun P. Mohanan * @param yield - context object that represents the currently executing 145106584cd0SArun P. Mohanan * coroutine 145206584cd0SArun P. Mohanan * @param feature - feature enum to enable or disable 145306584cd0SArun P. Mohanan * @param enable - enable or disable the feature 145406584cd0SArun P. Mohanan * @param featureArg - custom arguments for that feature 145506584cd0SArun P. Mohanan * @param reserved - reserved for future use 145606584cd0SArun P. Mohanan * 145706584cd0SArun P. Mohanan * @returns IPMI completion code 145806584cd0SArun P. Mohanan */ 145906584cd0SArun P. Mohanan ipmi::RspType<> mtmBMCFeatureControl(ipmi::Context::ptr ctx, 146006584cd0SArun P. Mohanan const uint8_t feature, 146106584cd0SArun P. Mohanan const uint8_t enable, 146206584cd0SArun P. Mohanan const uint8_t featureArg, 146306584cd0SArun P. Mohanan const uint16_t reserved) 146406584cd0SArun P. Mohanan { 146506584cd0SArun P. Mohanan if (reserved != 0) 146606584cd0SArun P. Mohanan { 146706584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 146806584cd0SArun P. Mohanan } 146906584cd0SArun P. Mohanan 147006584cd0SArun P. Mohanan switch (feature) 147106584cd0SArun P. Mohanan { 147206584cd0SArun P. Mohanan case ipmi::SupportedFeatureControls::mctp: 147306584cd0SArun P. Mohanan switch (featureArg) 147406584cd0SArun P. Mohanan { 147506584cd0SArun P. Mohanan case ipmi::SupportedMCTPBindings::mctpPCIe: 147606584cd0SArun P. Mohanan return handleMCTPFeature(ctx, enable, "MCTP_PCIe"); 147706584cd0SArun P. Mohanan case ipmi::SupportedMCTPBindings::mctpSMBusHSBP: 147806584cd0SArun P. Mohanan return handleMCTPFeature(ctx, enable, "MCTP_SMBus_HSBP"); 147906584cd0SArun P. Mohanan case ipmi::SupportedMCTPBindings::mctpSMBusPCIeSlot: 148006584cd0SArun P. Mohanan return handleMCTPFeature(ctx, enable, 148106584cd0SArun P. Mohanan "MCTP_SMBus_PCIe_slot"); 148206584cd0SArun P. Mohanan default: 148306584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 148406584cd0SArun P. Mohanan } 148506584cd0SArun P. Mohanan break; 14865cb2c045SJason M. Bills case ipmi::SupportedFeatureControls::pcieScan: 14875cb2c045SJason M. Bills if (featureArg != 0) 14885cb2c045SJason M. Bills { 14895cb2c045SJason M. Bills return ipmi::responseInvalidFieldRequest(); 14905cb2c045SJason M. Bills } 14915cb2c045SJason M. Bills startOrStopService(ctx, enable, "xyz.openbmc_project.PCIe.service"); 14925cb2c045SJason M. Bills break; 149306584cd0SArun P. Mohanan default: 149406584cd0SArun P. Mohanan return ipmi::responseInvalidFieldRequest(); 149506584cd0SArun P. Mohanan } 149606584cd0SArun P. Mohanan return ipmi::responseSuccess(); 149706584cd0SArun P. Mohanan } 1498a3702c1fSVernon Mauery } // namespace ipmi 1499a3702c1fSVernon Mauery 1500a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor)); 1501a3702c1fSVernon Mauery void register_mtm_commands() 1502a3702c1fSVernon Mauery { 150338d2b5a6SJason M. Bills // <Get SM Signal> 150498bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 150598bbf69aSVernon Mauery ipmi::intel::general::cmdGetSmSignal, 15065e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMGetSignal); 1507a3702c1fSVernon Mauery 150898bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 150998bbf69aSVernon Mauery ipmi::intel::general::cmdSetSmSignal, 15105e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMSetSignal); 1511a3702c1fSVernon Mauery 151298bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 151398bbf69aSVernon Mauery ipmi::intel::general::cmdMtmKeepAlive, 1514666dd01cSRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::mtmKeepAlive); 1515666dd01cSRichard Marian Thomaiyar 151698bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 151798bbf69aSVernon Mauery ipmi::intel::general::cmdSetManufacturingData, 15181f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::setManufacturingData); 15191f0839c2SRichard Marian Thomaiyar 152098bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 152198bbf69aSVernon Mauery ipmi::intel::general::cmdGetManufacturingData, 15221f0839c2SRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::getManufacturingData); 15231f0839c2SRichard Marian Thomaiyar 152427d2356eSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 152527d2356eSVernon Mauery ipmi::intel::general::cmdSetFITcLayout, 152627d2356eSVernon Mauery ipmi::Privilege::Admin, ipmi::setFITcLayout); 152727d2356eSVernon Mauery 152806584cd0SArun P. Mohanan ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnGeneral, 152906584cd0SArun P. Mohanan ipmi::intel::general::cmdMTMBMCFeatureControl, 153006584cd0SArun P. Mohanan ipmi::Privilege::Admin, ipmi::mtmBMCFeatureControl); 153106584cd0SArun P. Mohanan 153298bbf69aSVernon Mauery ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnApp, 153398bbf69aSVernon Mauery ipmi::intel::general::cmdSlotI2CMasterWriteRead, 153498bbf69aSVernon Mauery ipmi::Privilege::Admin, 153598bbf69aSVernon Mauery ipmi::appSlotI2CMasterWriteRead); 1536f267a67dSYong Li 1537068b4f2cSYong Li ipmi::registerHandler(ipmi::prioOemBase, ipmi::intel::netFnPlatform, 1538068b4f2cSYong Li ipmi::intel::platform::cmdClearCMOS, 1539068b4f2cSYong Li ipmi::Privilege::Admin, ipmi::clearCMOS); 1540068b4f2cSYong Li 154198bbf69aSVernon Mauery ipmi::registerFilter(ipmi::prioOemBase, 154285feb130SYong Li [](ipmi::message::Request::ptr request) { 154385feb130SYong Li return ipmi::mfgFilterMessage(request); 154485feb130SYong Li }); 1545a3702c1fSVernon Mauery } 1546