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 17147daec5SRichard Marian Thomaiyar #include <boost/container/flat_map.hpp> 181b74a210SRichard Marian Thomaiyar #include <fstream> 19a3702c1fSVernon Mauery #include <ipmid/api.hpp> 20a3702c1fSVernon Mauery #include <manufacturingcommands.hpp> 21a3702c1fSVernon Mauery #include <oemcommands.hpp> 22a3702c1fSVernon Mauery 23a3702c1fSVernon Mauery namespace ipmi 24a3702c1fSVernon Mauery { 25a3702c1fSVernon Mauery 26a3702c1fSVernon Mauery Manufacturing mtm; 27a3702c1fSVernon Mauery 28a3702c1fSVernon Mauery static auto revertTimeOut = 29a3702c1fSVernon Mauery std::chrono::duration_cast<std::chrono::microseconds>( 30a3702c1fSVernon Mauery std::chrono::seconds(60)); // 1 minute timeout 31a3702c1fSVernon Mauery 32a3702c1fSVernon Mauery static constexpr const char* callbackMgrService = 33a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 34a3702c1fSVernon Mauery static constexpr const char* callbackMgrIntf = 35a3702c1fSVernon Mauery "xyz.openbmc_project.CallbackManager"; 36a3702c1fSVernon Mauery static constexpr const char* callbackMgrObjPath = 37a3702c1fSVernon Mauery "/xyz/openbmc_project/CallbackManager"; 38a3702c1fSVernon Mauery static constexpr const char* retriggerLedUpdate = "RetriggerLEDUpdate"; 39a3702c1fSVernon Mauery 40a3702c1fSVernon Mauery const static constexpr char* systemDService = "org.freedesktop.systemd1"; 41a3702c1fSVernon Mauery const static constexpr char* systemDObjPath = "/org/freedesktop/systemd1"; 42a3702c1fSVernon Mauery const static constexpr char* systemDMgrIntf = 43a3702c1fSVernon Mauery "org.freedesktop.systemd1.Manager"; 44a3702c1fSVernon Mauery const static constexpr char* pidControlService = "phosphor-pid-control.service"; 45a3702c1fSVernon Mauery 46666dd01cSRichard Marian Thomaiyar static inline Cc resetMtmTimer(boost::asio::yield_context yield) 47666dd01cSRichard Marian Thomaiyar { 48666dd01cSRichard Marian Thomaiyar auto sdbusp = getSdBus(); 49666dd01cSRichard Marian Thomaiyar boost::system::error_code ec; 50666dd01cSRichard Marian Thomaiyar sdbusp->yield_method_call<>(yield, ec, specialModeService, 51666dd01cSRichard Marian Thomaiyar specialModeObjPath, specialModeIntf, 52666dd01cSRichard Marian Thomaiyar "ResetTimer"); 53666dd01cSRichard Marian Thomaiyar if (ec) 54666dd01cSRichard Marian Thomaiyar { 55666dd01cSRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 56666dd01cSRichard Marian Thomaiyar "Failed to reset the manufacturing mode timer"); 57666dd01cSRichard Marian Thomaiyar return ccUnspecifiedError; 58666dd01cSRichard Marian Thomaiyar } 59666dd01cSRichard Marian Thomaiyar return ccSuccess; 60666dd01cSRichard Marian Thomaiyar } 61666dd01cSRichard Marian Thomaiyar 6238d2b5a6SJason M. Bills int getGpioPathForSmSignal(const SmSignalGet signal, std::string& path) 63a3702c1fSVernon Mauery { 6438d2b5a6SJason M. Bills switch (signal) 6538d2b5a6SJason M. Bills { 6638d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 6738d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/power"; 6838d2b5a6SJason M. Bills break; 6938d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 7038d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/reset"; 7138d2b5a6SJason M. Bills break; 7238d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 7338d2b5a6SJason M. Bills path = "/xyz/openbmc_project/chassis/buttons/nmi"; 7438d2b5a6SJason M. Bills break; 758e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 768e5e2b04SRichard Marian Thomaiyar path = "/xyz/openbmc_project/chassis/buttons/id"; 778e5e2b04SRichard Marian Thomaiyar break; 7838d2b5a6SJason M. Bills default: 7938d2b5a6SJason M. Bills return -1; 8038d2b5a6SJason M. Bills break; 8138d2b5a6SJason M. Bills } 8238d2b5a6SJason M. Bills return 0; 83a3702c1fSVernon Mauery } 84a3702c1fSVernon Mauery 85a3702c1fSVernon Mauery ipmi_ret_t ledStoreAndSet(SmSignalSet signal, std::string setState) 86a3702c1fSVernon Mauery { 87a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 88a3702c1fSVernon Mauery if (ledProp == nullptr) 89a3702c1fSVernon Mauery { 90a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 91a3702c1fSVernon Mauery } 92a3702c1fSVernon Mauery 93a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 94a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 95a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 96a3702c1fSVernon Mauery ipmi::Value presentState; 97a3702c1fSVernon Mauery 98a3702c1fSVernon Mauery if (false == ledProp->getLock()) 99a3702c1fSVernon Mauery { 100a3702c1fSVernon Mauery if (mtm.getProperty(ledService.c_str(), ledPath.c_str(), ledIntf, 101a3702c1fSVernon Mauery "State", &presentState) != 0) 102a3702c1fSVernon Mauery { 103a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 104a3702c1fSVernon Mauery } 105a3702c1fSVernon Mauery ledProp->setPrevState(std::get<std::string>(presentState)); 106a3702c1fSVernon Mauery ledProp->setLock(true); 107a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 108a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 109a3702c1fSVernon Mauery { 110a3702c1fSVernon Mauery mtm.revertLedCallback = true; 111a3702c1fSVernon Mauery } 112a3702c1fSVernon Mauery } 11338d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 114a3702c1fSVernon Mauery ledStateStr + setState) != 0) 115a3702c1fSVernon Mauery { 116a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 117a3702c1fSVernon Mauery } 118a3702c1fSVernon Mauery return IPMI_CC_OK; 119a3702c1fSVernon Mauery } 120a3702c1fSVernon Mauery 121a3702c1fSVernon Mauery ipmi_ret_t ledRevert(SmSignalSet signal) 122a3702c1fSVernon Mauery { 123a3702c1fSVernon Mauery LedProperty* ledProp = mtm.findLedProperty(signal); 124a3702c1fSVernon Mauery if (ledProp == nullptr) 125a3702c1fSVernon Mauery { 126a3702c1fSVernon Mauery return IPMI_CC_INVALID_FIELD_REQUEST; 127a3702c1fSVernon Mauery } 128a3702c1fSVernon Mauery if (true == ledProp->getLock()) 129a3702c1fSVernon Mauery { 130a3702c1fSVernon Mauery ledProp->setLock(false); 131a3702c1fSVernon Mauery if (signal == SmSignalSet::smPowerFaultLed || 132a3702c1fSVernon Mauery signal == SmSignalSet::smSystemReadyLed) 133a3702c1fSVernon Mauery { 134a3702c1fSVernon Mauery try 135a3702c1fSVernon Mauery { 136a3702c1fSVernon Mauery ipmi::method_no_args::callDbusMethod( 137a3702c1fSVernon Mauery *getSdBus(), callbackMgrService, callbackMgrObjPath, 138a3702c1fSVernon Mauery callbackMgrIntf, retriggerLedUpdate); 139a3702c1fSVernon Mauery } 140a3702c1fSVernon Mauery catch (sdbusplus::exception_t& e) 141a3702c1fSVernon Mauery { 142a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 143a3702c1fSVernon Mauery } 144a3702c1fSVernon Mauery mtm.revertLedCallback = false; 145a3702c1fSVernon Mauery } 146a3702c1fSVernon Mauery else 147a3702c1fSVernon Mauery { 148a3702c1fSVernon Mauery std::string ledName = ledProp->getName(); 149a3702c1fSVernon Mauery std::string ledService = ledServicePrefix + ledName; 150a3702c1fSVernon Mauery std::string ledPath = ledPathPrefix + ledName; 15138d2b5a6SJason M. Bills if (mtm.setProperty(ledService, ledPath, ledIntf, "State", 15238d2b5a6SJason M. Bills ledProp->getPrevState()) != 0) 153a3702c1fSVernon Mauery { 154a3702c1fSVernon Mauery return IPMI_CC_UNSPECIFIED_ERROR; 155a3702c1fSVernon Mauery } 156a3702c1fSVernon Mauery } 157a3702c1fSVernon Mauery } 158a3702c1fSVernon Mauery return IPMI_CC_OK; 159a3702c1fSVernon Mauery } 160a3702c1fSVernon Mauery 161a3702c1fSVernon Mauery void Manufacturing::initData() 162a3702c1fSVernon Mauery { 163a3702c1fSVernon Mauery ledPropertyList.push_back( 164a3702c1fSVernon Mauery LedProperty(SmSignalSet::smPowerFaultLed, "status_amber")); 165a3702c1fSVernon Mauery ledPropertyList.push_back( 166a3702c1fSVernon Mauery LedProperty(SmSignalSet::smSystemReadyLed, "status_green")); 167a3702c1fSVernon Mauery ledPropertyList.push_back( 168a3702c1fSVernon Mauery LedProperty(SmSignalSet::smIdentifyLed, "identify")); 169a3702c1fSVernon Mauery } 170a3702c1fSVernon Mauery 171a3702c1fSVernon Mauery void Manufacturing::revertTimerHandler() 172a3702c1fSVernon Mauery { 173a3702c1fSVernon Mauery if (revertFanPWM) 174a3702c1fSVernon Mauery { 175a3702c1fSVernon Mauery revertFanPWM = false; 176a3702c1fSVernon Mauery disablePidControlService(false); 177a3702c1fSVernon Mauery } 178a3702c1fSVernon Mauery 179a3702c1fSVernon Mauery for (const auto& ledProperty : ledPropertyList) 180a3702c1fSVernon Mauery { 181a3702c1fSVernon Mauery const std::string& ledName = ledProperty.getName(); 182a3702c1fSVernon Mauery ledRevert(ledProperty.getSignal()); 183a3702c1fSVernon Mauery } 184a3702c1fSVernon Mauery } 185a3702c1fSVernon Mauery 186a3702c1fSVernon Mauery Manufacturing::Manufacturing() : 187a3702c1fSVernon Mauery revertTimer([&](void) { revertTimerHandler(); }) 188a3702c1fSVernon Mauery { 189a3702c1fSVernon Mauery initData(); 190a3702c1fSVernon Mauery } 191a3702c1fSVernon Mauery 19238d2b5a6SJason M. Bills int8_t Manufacturing::getProperty(const std::string& service, 19338d2b5a6SJason M. Bills const std::string& path, 19438d2b5a6SJason M. Bills const std::string& interface, 19538d2b5a6SJason M. Bills const std::string& propertyName, 19638d2b5a6SJason M. Bills ipmi::Value* reply) 197a3702c1fSVernon Mauery { 198a3702c1fSVernon Mauery try 199a3702c1fSVernon Mauery { 20038d2b5a6SJason M. Bills *reply = ipmi::getDbusProperty(*getSdBus(), service, path, interface, 20138d2b5a6SJason M. Bills propertyName); 202a3702c1fSVernon Mauery } 203a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 204a3702c1fSVernon Mauery { 205a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 206a3702c1fSVernon Mauery "ERROR: getProperty"); 207a3702c1fSVernon Mauery return -1; 208a3702c1fSVernon Mauery } 209a3702c1fSVernon Mauery 210a3702c1fSVernon Mauery return 0; 211a3702c1fSVernon Mauery } 212a3702c1fSVernon Mauery 21338d2b5a6SJason M. Bills int8_t Manufacturing::setProperty(const std::string& service, 21438d2b5a6SJason M. Bills const std::string& path, 21538d2b5a6SJason M. Bills const std::string& interface, 21638d2b5a6SJason M. Bills const std::string& propertyName, 21738d2b5a6SJason M. Bills ipmi::Value value) 218a3702c1fSVernon Mauery { 219a3702c1fSVernon Mauery try 220a3702c1fSVernon Mauery { 22138d2b5a6SJason M. Bills ipmi::setDbusProperty(*getSdBus(), service, path, interface, 222a3702c1fSVernon Mauery propertyName, value); 223a3702c1fSVernon Mauery } 224a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 225a3702c1fSVernon Mauery { 226a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 227a3702c1fSVernon Mauery "ERROR: setProperty"); 228a3702c1fSVernon Mauery return -1; 229a3702c1fSVernon Mauery } 230a3702c1fSVernon Mauery 231a3702c1fSVernon Mauery return 0; 232a3702c1fSVernon Mauery } 233a3702c1fSVernon Mauery 234a3702c1fSVernon Mauery int8_t Manufacturing::disablePidControlService(const bool disable) 235a3702c1fSVernon Mauery { 236a3702c1fSVernon Mauery try 237a3702c1fSVernon Mauery { 238a3702c1fSVernon Mauery auto dbus = getSdBus(); 239a3702c1fSVernon Mauery auto method = dbus->new_method_call(systemDService, systemDObjPath, 240a3702c1fSVernon Mauery systemDMgrIntf, 241a3702c1fSVernon Mauery disable ? "StopUnit" : "StartUnit"); 242a3702c1fSVernon Mauery method.append(pidControlService, "replace"); 243a3702c1fSVernon Mauery auto reply = dbus->call(method); 244a3702c1fSVernon Mauery } 245a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& e) 246a3702c1fSVernon Mauery { 247a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 248a3702c1fSVernon Mauery "ERROR: phosphor-pid-control service start or stop failed"); 249a3702c1fSVernon Mauery return -1; 250a3702c1fSVernon Mauery } 251a3702c1fSVernon Mauery return 0; 252a3702c1fSVernon Mauery } 253a3702c1fSVernon Mauery 25438d2b5a6SJason M. Bills ipmi::RspType<uint8_t, // Signal value 25538d2b5a6SJason M. Bills std::optional<uint16_t> // Fan tach value 25638d2b5a6SJason M. Bills > 257147daec5SRichard Marian Thomaiyar appMTMGetSignal(boost::asio::yield_context yield, uint8_t signalTypeByte, 258147daec5SRichard Marian Thomaiyar uint8_t instance, uint8_t actionByte) 259a3702c1fSVernon Mauery { 26038d2b5a6SJason M. Bills if (mtm.getAccessLvl() < MtmLvl::mtmAvailable) 26138d2b5a6SJason M. Bills { 26238d2b5a6SJason M. Bills return ipmi::responseInvalidCommand(); 26338d2b5a6SJason M. Bills } 26438d2b5a6SJason M. Bills 26538d2b5a6SJason M. Bills SmSignalGet signalType = static_cast<SmSignalGet>(signalTypeByte); 26638d2b5a6SJason M. Bills SmActionGet action = static_cast<SmActionGet>(actionByte); 26738d2b5a6SJason M. Bills 26838d2b5a6SJason M. Bills switch (signalType) 26938d2b5a6SJason M. Bills { 27038d2b5a6SJason M. Bills case SmSignalGet::smFanPwmGet: 27138d2b5a6SJason M. Bills { 272a3702c1fSVernon Mauery ipmi::Value reply; 273147daec5SRichard Marian Thomaiyar std::string fullPath = fanPwmPath + std::to_string(instance + 1); 27438d2b5a6SJason M. Bills if (mtm.getProperty(fanService, fullPath, fanIntf, "Value", 27538d2b5a6SJason M. Bills &reply) < 0) 27638d2b5a6SJason M. Bills { 27738d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 27838d2b5a6SJason M. Bills } 27938d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 28038d2b5a6SJason M. Bills if (doubleVal == nullptr) 28138d2b5a6SJason M. Bills { 28238d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 28338d2b5a6SJason M. Bills } 28438d2b5a6SJason M. Bills uint8_t sensorVal = std::round(*doubleVal); 2854cc10159SRichard Marian Thomaiyar resetMtmTimer(yield); 28638d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 28738d2b5a6SJason M. Bills } 28838d2b5a6SJason M. Bills break; 28938d2b5a6SJason M. Bills case SmSignalGet::smFanTachometerGet: 29038d2b5a6SJason M. Bills { 291147daec5SRichard Marian Thomaiyar auto sdbusp = getSdBus(); 292147daec5SRichard Marian Thomaiyar boost::system::error_code ec; 293147daec5SRichard Marian Thomaiyar using objFlatMap = boost::container::flat_map< 294147daec5SRichard Marian Thomaiyar std::string, boost::container::flat_map< 295147daec5SRichard Marian Thomaiyar std::string, std::vector<std::string>>>; 296147daec5SRichard Marian Thomaiyar 297147daec5SRichard Marian Thomaiyar auto flatMap = sdbusp->yield_method_call<objFlatMap>( 298147daec5SRichard Marian Thomaiyar yield, ec, "xyz.openbmc_project.ObjectMapper", 299147daec5SRichard Marian Thomaiyar "/xyz/openbmc_project/object_mapper", 300147daec5SRichard Marian Thomaiyar "xyz.openbmc_project.ObjectMapper", "GetSubTree", 301147daec5SRichard Marian Thomaiyar fanTachBasePath, 0, std::array<const char*, 1>{fanIntf}); 302147daec5SRichard Marian Thomaiyar if (ec) 303147daec5SRichard Marian Thomaiyar { 304147daec5SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>( 305147daec5SRichard Marian Thomaiyar "Failed to query fan tach sub tree objects"); 306147daec5SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 307147daec5SRichard Marian Thomaiyar } 308147daec5SRichard Marian Thomaiyar if (instance >= flatMap.size()) 30938d2b5a6SJason M. Bills { 31038d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 31138d2b5a6SJason M. Bills } 312147daec5SRichard Marian Thomaiyar auto itr = flatMap.nth(instance); 31338d2b5a6SJason M. Bills ipmi::Value reply; 314147daec5SRichard Marian Thomaiyar if (mtm.getProperty(fanService, itr->first, fanIntf, "Value", 31538d2b5a6SJason M. Bills &reply) < 0) 31638d2b5a6SJason M. Bills { 31738d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 31838d2b5a6SJason M. Bills } 31938d2b5a6SJason M. Bills 32038d2b5a6SJason M. Bills double* doubleVal = std::get_if<double>(&reply); 32138d2b5a6SJason M. Bills if (doubleVal == nullptr) 32238d2b5a6SJason M. Bills { 32338d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 32438d2b5a6SJason M. Bills } 32538d2b5a6SJason M. Bills uint8_t sensorVal = FAN_PRESENT | FAN_SENSOR_PRESENT; 32638d2b5a6SJason M. Bills std::optional<uint16_t> fanTach = std::round(*doubleVal); 32738d2b5a6SJason M. Bills 3284cc10159SRichard Marian Thomaiyar resetMtmTimer(yield); 32938d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, fanTach); 33038d2b5a6SJason M. Bills } 33138d2b5a6SJason M. Bills break; 3328e5e2b04SRichard Marian Thomaiyar case SmSignalGet::smIdentifyButton: 3338e5e2b04SRichard Marian Thomaiyar { 3348e5e2b04SRichard Marian Thomaiyar if (action == SmActionGet::revert || action == SmActionGet::ignore) 3358e5e2b04SRichard Marian Thomaiyar { 3368e5e2b04SRichard Marian Thomaiyar // ButtonMasked property is not supported for ID button as it is 3378e5e2b04SRichard Marian Thomaiyar // unnecessary. Hence if requested for revert / ignore, override 3388e5e2b04SRichard Marian Thomaiyar // it to sample action to make tools happy. 3398e5e2b04SRichard Marian Thomaiyar action = SmActionGet::sample; 3408e5e2b04SRichard Marian Thomaiyar } 3418e5e2b04SRichard Marian Thomaiyar // fall-through 3428e5e2b04SRichard Marian Thomaiyar } 34338d2b5a6SJason M. Bills case SmSignalGet::smResetButton: 34438d2b5a6SJason M. Bills case SmSignalGet::smPowerButton: 34538d2b5a6SJason M. Bills case SmSignalGet::smNMIButton: 34638d2b5a6SJason M. Bills { 34738d2b5a6SJason M. Bills std::string path; 34838d2b5a6SJason M. Bills if (getGpioPathForSmSignal(signalType, path) < 0) 34938d2b5a6SJason M. Bills { 35038d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 35138d2b5a6SJason M. Bills } 352a3702c1fSVernon Mauery 353a3702c1fSVernon Mauery switch (action) 354a3702c1fSVernon Mauery { 355a3702c1fSVernon Mauery case SmActionGet::sample: 356a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 357a3702c1fSVernon Mauery "case SmActionGet::sample"); 358a3702c1fSVernon Mauery break; 359a3702c1fSVernon Mauery case SmActionGet::ignore: 360a3702c1fSVernon Mauery { 361a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 362a3702c1fSVernon Mauery "case SmActionGet::ignore"); 36338d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 36438d2b5a6SJason M. Bills "ButtonMasked", true) < 0) 365a3702c1fSVernon Mauery { 36638d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 367a3702c1fSVernon Mauery } 368a3702c1fSVernon Mauery } 369a3702c1fSVernon Mauery break; 370a3702c1fSVernon Mauery case SmActionGet::revert: 371a3702c1fSVernon Mauery { 372a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 373a3702c1fSVernon Mauery "case SmActionGet::revert"); 37438d2b5a6SJason M. Bills if (mtm.setProperty(buttonService, path, buttonIntf, 37538d2b5a6SJason M. Bills "ButtonMasked", false) < 0) 376a3702c1fSVernon Mauery { 37738d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 378a3702c1fSVernon Mauery } 379a3702c1fSVernon Mauery } 380a3702c1fSVernon Mauery break; 381a3702c1fSVernon Mauery 382a3702c1fSVernon Mauery default: 38338d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 384a3702c1fSVernon Mauery break; 385a3702c1fSVernon Mauery } 386a3702c1fSVernon Mauery 387a3702c1fSVernon Mauery ipmi::Value reply; 38838d2b5a6SJason M. Bills if (mtm.getProperty(buttonService, path, buttonIntf, 38938d2b5a6SJason M. Bills "ButtonPressed", &reply) < 0) 390a3702c1fSVernon Mauery { 39138d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 392a3702c1fSVernon Mauery } 39338d2b5a6SJason M. Bills bool* valPtr = std::get_if<bool>(&reply); 39438d2b5a6SJason M. Bills if (valPtr == nullptr) 395a3702c1fSVernon Mauery { 39638d2b5a6SJason M. Bills return ipmi::responseUnspecifiedError(); 397a3702c1fSVernon Mauery } 3984cc10159SRichard Marian Thomaiyar resetMtmTimer(yield); 39938d2b5a6SJason M. Bills uint8_t sensorVal = *valPtr; 40038d2b5a6SJason M. Bills return ipmi::responseSuccess(sensorVal, std::nullopt); 401a3702c1fSVernon Mauery } 402a3702c1fSVernon Mauery break; 4031b74a210SRichard Marian Thomaiyar case SmSignalGet::smNcsiDiag: 4041b74a210SRichard Marian Thomaiyar { 4051b74a210SRichard Marian Thomaiyar constexpr const char* netBasePath = "/sys/class/net/eth"; 4061b74a210SRichard Marian Thomaiyar constexpr const char* carrierSuffix = "/carrier"; 4071b74a210SRichard Marian Thomaiyar std::ifstream netIfs(netBasePath + std::to_string(instance) + 4081b74a210SRichard Marian Thomaiyar carrierSuffix); 4091b74a210SRichard Marian Thomaiyar if (!netIfs.good()) 4101b74a210SRichard Marian Thomaiyar { 4111b74a210SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 4121b74a210SRichard Marian Thomaiyar } 4131b74a210SRichard Marian Thomaiyar std::string carrier; 4141b74a210SRichard Marian Thomaiyar netIfs >> carrier; 4151b74a210SRichard Marian Thomaiyar resetMtmTimer(yield); 4161b74a210SRichard Marian Thomaiyar return ipmi::responseSuccess( 4171b74a210SRichard Marian Thomaiyar static_cast<uint8_t>(std::stoi(carrier)), std::nullopt); 4181b74a210SRichard Marian Thomaiyar } 4191b74a210SRichard Marian Thomaiyar break; 420a3702c1fSVernon Mauery default: 42138d2b5a6SJason M. Bills return ipmi::responseInvalidFieldRequest(); 422a3702c1fSVernon Mauery break; 423a3702c1fSVernon Mauery } 424a3702c1fSVernon Mauery } 425a3702c1fSVernon Mauery 4264cc10159SRichard Marian Thomaiyar ipmi::RspType<> appMTMSetSignal(boost::asio::yield_context yield, 4274cc10159SRichard Marian Thomaiyar uint8_t signalTypeByte, uint8_t instance, 4285e3bf557SAyushi Smriti uint8_t actionByte, 4295e3bf557SAyushi Smriti std::optional<uint8_t> pwmSpeed) 430a3702c1fSVernon Mauery { 4315e3bf557SAyushi Smriti if (mtm.getAccessLvl() < MtmLvl::mtmAvailable) 4325e3bf557SAyushi Smriti { 4335e3bf557SAyushi Smriti return ipmi::responseInvalidCommand(); 4345e3bf557SAyushi Smriti } 4355e3bf557SAyushi Smriti 4365e3bf557SAyushi Smriti SmSignalSet signalType = static_cast<SmSignalSet>(signalTypeByte); 4375e3bf557SAyushi Smriti SmActionSet action = static_cast<SmActionSet>(actionByte); 4385e3bf557SAyushi Smriti Cc retCode = ccSuccess; 43913b0039dSJames Feist int8_t ret = 0; 4405e3bf557SAyushi Smriti 4415e3bf557SAyushi Smriti switch (signalType) 442a3702c1fSVernon Mauery { 443a3702c1fSVernon Mauery case SmSignalSet::smPowerFaultLed: 444a3702c1fSVernon Mauery case SmSignalSet::smSystemReadyLed: 445a3702c1fSVernon Mauery case SmSignalSet::smIdentifyLed: 4465e3bf557SAyushi Smriti switch (action) 447a3702c1fSVernon Mauery { 448a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 449a3702c1fSVernon Mauery { 450a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 451a3702c1fSVernon Mauery "case SmActionSet::forceDeasserted"); 452a3702c1fSVernon Mauery 4535e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("Off")); 4545e3bf557SAyushi Smriti if (retCode != ccSuccess) 455a3702c1fSVernon Mauery { 4565e3bf557SAyushi Smriti return ipmi::response(retCode); 457a3702c1fSVernon Mauery } 458a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 459a3702c1fSVernon Mauery } 460a3702c1fSVernon Mauery break; 461a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 462a3702c1fSVernon Mauery { 463a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 464a3702c1fSVernon Mauery "case SmActionSet::forceAsserted"); 465a3702c1fSVernon Mauery 4665e3bf557SAyushi Smriti retCode = ledStoreAndSet(signalType, std::string("On")); 4675e3bf557SAyushi Smriti if (retCode != ccSuccess) 468a3702c1fSVernon Mauery { 4695e3bf557SAyushi Smriti return ipmi::response(retCode); 470a3702c1fSVernon Mauery } 471a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 4725e3bf557SAyushi Smriti if (SmSignalSet::smPowerFaultLed == signalType) 473a3702c1fSVernon Mauery { 474a3702c1fSVernon Mauery // Deassert "system ready" 4755e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smSystemReadyLed, 476a3702c1fSVernon Mauery std::string("Off")); 477a3702c1fSVernon Mauery } 4785e3bf557SAyushi Smriti else if (SmSignalSet::smSystemReadyLed == signalType) 479a3702c1fSVernon Mauery { 480a3702c1fSVernon Mauery // Deassert "fault led" 4815e3bf557SAyushi Smriti retCode = ledStoreAndSet(SmSignalSet::smPowerFaultLed, 482a3702c1fSVernon Mauery std::string("Off")); 483a3702c1fSVernon Mauery } 484a3702c1fSVernon Mauery } 485a3702c1fSVernon Mauery break; 486a3702c1fSVernon Mauery case SmActionSet::revert: 487a3702c1fSVernon Mauery { 488a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::INFO>( 489a3702c1fSVernon Mauery "case SmActionSet::revert"); 4905e3bf557SAyushi Smriti retCode = ledRevert(signalType); 491a3702c1fSVernon Mauery } 492a3702c1fSVernon Mauery break; 493a3702c1fSVernon Mauery default: 494a3702c1fSVernon Mauery { 4955e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 496a3702c1fSVernon Mauery } 497a3702c1fSVernon Mauery } 498a3702c1fSVernon Mauery break; 499a3702c1fSVernon Mauery case SmSignalSet::smFanPowerSpeed: 500a3702c1fSVernon Mauery { 5015e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (!pwmSpeed)) 502a3702c1fSVernon Mauery { 5035e3bf557SAyushi Smriti return ipmi::responseReqDataLenInvalid(); 504a3702c1fSVernon Mauery } 5055e3bf557SAyushi Smriti 5065e3bf557SAyushi Smriti if ((action == SmActionSet::forceAsserted) && (*pwmSpeed > 100)) 5075e3bf557SAyushi Smriti { 5085e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 5095e3bf557SAyushi Smriti } 5105e3bf557SAyushi Smriti 511a3702c1fSVernon Mauery uint8_t pwmValue = 0; 5125e3bf557SAyushi Smriti switch (action) 513a3702c1fSVernon Mauery { 514a3702c1fSVernon Mauery case SmActionSet::revert: 515a3702c1fSVernon Mauery { 516a3702c1fSVernon Mauery if (mtm.revertFanPWM) 517a3702c1fSVernon Mauery { 518a3702c1fSVernon Mauery ret = mtm.disablePidControlService(false); 519a3702c1fSVernon Mauery if (ret < 0) 520a3702c1fSVernon Mauery { 5215e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 522a3702c1fSVernon Mauery } 523a3702c1fSVernon Mauery mtm.revertFanPWM = false; 524a3702c1fSVernon Mauery } 525a3702c1fSVernon Mauery } 526a3702c1fSVernon Mauery break; 527a3702c1fSVernon Mauery case SmActionSet::forceAsserted: 528a3702c1fSVernon Mauery { 5295e3bf557SAyushi Smriti pwmValue = *pwmSpeed; 530a3702c1fSVernon Mauery } // fall-through 531a3702c1fSVernon Mauery case SmActionSet::forceDeasserted: 532a3702c1fSVernon Mauery { 533a3702c1fSVernon Mauery if (!mtm.revertFanPWM) 534a3702c1fSVernon Mauery { 535a3702c1fSVernon Mauery ret = mtm.disablePidControlService(true); 536a3702c1fSVernon Mauery if (ret < 0) 537a3702c1fSVernon Mauery { 5385e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 539a3702c1fSVernon Mauery } 540a3702c1fSVernon Mauery mtm.revertFanPWM = true; 541a3702c1fSVernon Mauery } 542a3702c1fSVernon Mauery mtm.revertTimer.start(revertTimeOut); 543a3702c1fSVernon Mauery std::string fanPwmInstancePath = 5445e3bf557SAyushi Smriti fanPwmPath + std::to_string(instance + 1); 545a3702c1fSVernon Mauery 5465e3bf557SAyushi Smriti ret = 5475e3bf557SAyushi Smriti mtm.setProperty(fanService, fanPwmInstancePath, fanIntf, 5485e3bf557SAyushi Smriti "Value", static_cast<double>(pwmValue)); 549a3702c1fSVernon Mauery if (ret < 0) 550a3702c1fSVernon Mauery { 5515e3bf557SAyushi Smriti return ipmi::responseUnspecifiedError(); 552a3702c1fSVernon Mauery } 553a3702c1fSVernon Mauery } 554a3702c1fSVernon Mauery break; 555a3702c1fSVernon Mauery default: 556a3702c1fSVernon Mauery { 5575e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 558a3702c1fSVernon Mauery } 559a3702c1fSVernon Mauery } 560a3702c1fSVernon Mauery } 561a3702c1fSVernon Mauery break; 562a3702c1fSVernon Mauery default: 563a3702c1fSVernon Mauery { 5645e3bf557SAyushi Smriti return ipmi::responseInvalidFieldRequest(); 565a3702c1fSVernon Mauery } 566a3702c1fSVernon Mauery } 5674cc10159SRichard Marian Thomaiyar if (retCode == ccSuccess) 5684cc10159SRichard Marian Thomaiyar { 5694cc10159SRichard Marian Thomaiyar resetMtmTimer(yield); 5704cc10159SRichard Marian Thomaiyar } 5715e3bf557SAyushi Smriti return ipmi::response(retCode); 572a3702c1fSVernon Mauery } 573a3702c1fSVernon Mauery 574666dd01cSRichard Marian Thomaiyar ipmi::RspType<> mtmKeepAlive(boost::asio::yield_context yield, uint8_t reserved, 575666dd01cSRichard Marian Thomaiyar const std::array<char, 5>& intentionalSignature) 576666dd01cSRichard Marian Thomaiyar { 577666dd01cSRichard Marian Thomaiyar // Allow MTM keep alive command only in manfacturing mode. 578666dd01cSRichard Marian Thomaiyar if (mtm.getAccessLvl() != MtmLvl::mtmAvailable) 579666dd01cSRichard Marian Thomaiyar { 580666dd01cSRichard Marian Thomaiyar return ipmi::responseInvalidCommand(); 581666dd01cSRichard Marian Thomaiyar } 582666dd01cSRichard Marian Thomaiyar constexpr std::array<char, 5> signatureOk = {'I', 'N', 'T', 'E', 'L'}; 583666dd01cSRichard Marian Thomaiyar if (intentionalSignature != signatureOk || reserved != 0) 584666dd01cSRichard Marian Thomaiyar { 585666dd01cSRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 586666dd01cSRichard Marian Thomaiyar } 587666dd01cSRichard Marian Thomaiyar return ipmi::response(resetMtmTimer(yield)); 588666dd01cSRichard Marian Thomaiyar } 589666dd01cSRichard Marian Thomaiyar 590*85feb130SYong Li ipmi::Cc mfgFilterMessage(ipmi::message::Request::ptr request) 591*85feb130SYong Li { 592*85feb130SYong Li // i2c master write read command needs additional checking 593*85feb130SYong Li if ((request->ctx->netFn == ipmi::netFnApp) && 594*85feb130SYong Li (request->ctx->cmd == ipmi::app::cmdMasterWriteRead)) 595*85feb130SYong Li { 596*85feb130SYong Li if (request->payload.size() > 4) 597*85feb130SYong Li { 598*85feb130SYong Li // Allow write data count > 1, only if it is in MFG mode 599*85feb130SYong Li if (mtm.getAccessLvl() != MtmLvl::mtmAvailable) 600*85feb130SYong Li { 601*85feb130SYong Li return ipmi::ccInsufficientPrivilege; 602*85feb130SYong Li } 603*85feb130SYong Li } 604*85feb130SYong Li } 605*85feb130SYong Li 606*85feb130SYong Li return ipmi::ccSuccess; 607*85feb130SYong Li } 608*85feb130SYong Li 609a3702c1fSVernon Mauery } // namespace ipmi 610a3702c1fSVernon Mauery 611a3702c1fSVernon Mauery void register_mtm_commands() __attribute__((constructor)); 612a3702c1fSVernon Mauery void register_mtm_commands() 613a3702c1fSVernon Mauery { 61438d2b5a6SJason M. Bills // <Get SM Signal> 61538d2b5a6SJason M. Bills ipmi::registerHandler( 61638d2b5a6SJason M. Bills ipmi::prioOemBase, ipmi::netFnOemOne, 617390b4354SRichard Marian Thomaiyar static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdGetSmSignal), 6185e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMGetSignal); 619a3702c1fSVernon Mauery 6205e3bf557SAyushi Smriti ipmi::registerHandler( 6215e3bf557SAyushi Smriti ipmi::prioOemBase, ipmi::netFnOemOne, 622390b4354SRichard Marian Thomaiyar static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdSetSmSignal), 6235e3bf557SAyushi Smriti ipmi::Privilege::Admin, ipmi::appMTMSetSignal); 624a3702c1fSVernon Mauery 625666dd01cSRichard Marian Thomaiyar ipmi::registerHandler( 626666dd01cSRichard Marian Thomaiyar ipmi::prioOemBase, ipmi::netFnOemOne, 627666dd01cSRichard Marian Thomaiyar static_cast<ipmi::Cmd>(IPMINetfnIntelOEMGeneralCmd::cmdMtmKeepAlive), 628666dd01cSRichard Marian Thomaiyar ipmi::Privilege::Admin, ipmi::mtmKeepAlive); 629666dd01cSRichard Marian Thomaiyar 630*85feb130SYong Li ipmi::registerFilter(ipmi::netFnOemOne, 631*85feb130SYong Li [](ipmi::message::Request::ptr request) { 632*85feb130SYong Li return ipmi::mfgFilterMessage(request); 633*85feb130SYong Li }); 634*85feb130SYong Li 635a3702c1fSVernon Mauery return; 636a3702c1fSVernon Mauery } 637